using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RB_MES_API.Context;
using RB_MES_API.Controllers.Cloud;
using RB_MES_API.Models;
using RB_MES_API.Models.Cloud;
using RB_MES_API.Models.Pangu;
using RB_MES_APICore.Models.Pangu;



using RB_MES_APICore.Models.Pangu;

//using RBMESAPI.Models.Cloud;

using RB_MES_APICore.Models.Pangu;
//using RBMESAPI.Models.Cloud;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace RB_MES_API.Controllers
{
    /// <summary>
    /// 专属Enpower的API接口
    /// </summary>
    [ApiController]
    [Route("[controller]")]
    public class ApiController : ControllerBase
    {
        private readonly RBContext _context;
        private readonly IShareController _shareController;
        private readonly IKDCloudHttpClient _KdhttpClient;
        private readonly ILogger _logger;
        private readonly IChiledSelect _chiledselect;
        private readonly IKDSqlHelper _kdsqlhelper;


        ///// <summary>
        ///// 需要查询的请求列表
        ///// </summary>
        //private IList<CloudBillQuery> queryJsons = new List<CloudBillQuery>();
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="context"></param>
        /// <param name="shareController"></param>
        /// <param name="kdhttpClient"></param>
        /// <param name="logger"></param>
        /// <param name="chiledSelect"></param>
        /// <param name="kdsqlhelper"></param>
        public ApiController(RBContext context, IShareController shareController, IKDCloudHttpClient kdhttpClient, 
            ILogger<EnpowerApiController> logger, IChiledSelect chiledSelect,IKDSqlHelper kdsqlhelper)
        {
            _context = context;
            _shareController = shareController;
            _KdhttpClient = kdhttpClient;
            _logger = logger;
            _chiledselect = chiledSelect;
            _kdsqlhelper = kdsqlhelper;
            //_pushmesinterface = pushmesinterface;
        }

        private void WritLog(string errstr)
        {
            _logger.LogInformation(DateTime.UtcNow.ToLongTimeString() + errstr);
        }
        
        /// <summary>
        /// MES从ERP里查询的JSON结构，逻辑判断符都是‘=’
        /// </summary>
        public class GetErpParameters
        {
            /// <summary>
            /// 查询类型
            /// </summary>
            public string DocType { get; set; } = string.Empty;
            /// <summary>
            /// 查询参数
            /// </summary>
            public Dictionary<string, object> KeyValues { get; set; }
        }

        public class RequestParm
        {
            /// <summary>
            /// 接口类型
            /// </summary>
            public string DocType { get; set; } = string.Empty;
            /// <summary>
            /// 发送的内容
            /// </summary>
            public object data { get; set; } = new object();

        }
        /// <summary>
        /// 根据SelectClumnConvert创建一个新的空表，准备装返回数据。暂时不用............
        /// </summary>
        /// <param name="clumnConvert">SelectClumnConvert</param>
        /// <returns></returns>
        private DataTable CreateDatatable(List<SelectClumnConvert> clumnConvert)
        {
            DataTable dataTable = new DataTable();
            var selectconvert = clumnConvert
                .Select(s => new { s.FIndexID, s.FDesTableName })
                .DistinctBy(s => new { s.FIndexID, s.FDesTableName })
                .OrderBy(s => s.FIndexID)
                .ToList();
            foreach (var selectClumnConvert in selectconvert)
            {
                dataTable.Columns.Add(selectClumnConvert.FDesTableName, typeof(string));
            }
            return dataTable;
        }

        private string UpdateDataRow_Unit(BD_UNIT unit, DataRow row)
        {
            string result = "UPDATE kdCloud_BD_UNIT SET ";
            string usql = "";
            Type type = typeof(BD_UNIT);
            PropertyInfo[] propertyInfos = type.GetProperties();
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                PropertyInfo propertyInfo = propertyInfos[i];
                string colname = propertyInfo.Name;
                if (row.Table.Columns.Contains(colname))
                {
                    object v= propertyInfo.GetValue(unit, null);
                     if (row[colname].Equals(v))
                    {
                        string sform =string.Format(colname + "='{0}'",v);
                        usql += usql == "" ? sform : "," + sform;
                    };
                }
            }
            if (usql != "")
            {
                return result + usql + string.Format(" where FUNITID={0}", unit.FUNITID);
            }
            return "";
        }
        private void AddDataRow_Unit(BD_UNIT unit, DataTable table)
        {
            DataRow row = table.NewRow();
            Type type= typeof(BD_UNIT);
            PropertyInfo[] propertyInfos = type.GetProperties();
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                PropertyInfo propertyInfo = propertyInfos[i];
                string colname=propertyInfo.Name;
                if (table.Columns.Contains(colname))
                {
                    row[colname]=propertyInfo.GetValue(unit, null);
                }
            }
            table.Rows.Add(row);
            table.AcceptChanges();
        }
        /// <summary>
        /// 云星空计量单位变动反向同步到沃比系统_初始化
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("UnitChangedinfo")]
        public async Task<string> UnitChangedinfo()
        {
            string messstr = string.Empty;
            string fileds = "FUNITID,FNumber,FName,FIsBaseUnit,FPrecision,FDocumentStatus,FForbidStatus,FConvertDenominator,FConvertNumerator,FRoundType";
            //从云星空中把所有计量单位获取过来
            CloudBillQueryJson queryJson = new CloudBillQueryJson()
            {
                FieldKeys = fileds,
                FormId = "BD_UNIT"
            };
            if (!_KdhttpClient.Islogin)
            {
                await _KdhttpClient.LoginErp();
            }
            //从云星空查询
            string jsonstr = JsonConvert.SerializeObject(queryJson);
            List<object> Parameters = new List<object>();
            Parameters.Add(jsonstr);
            _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
            _KdhttpClient.myurl = LocalStaticRequest.tokenurl + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc";
            //string result = _KdhttpClient.AsyncRequest();
            string result = await _KdhttpClient.AsyncClientRequest();
            //如果访问正常
            if (_KdhttpClient.CloudExecuteQueryStatus(result, ref messstr))
            {
                //将获取到的结果转为List<BD_UNIT>
                List<BD_UNIT> bDs = _shareController.GetNewObjForChild<BD_UNIT>(fileds, result, ref messstr);
                //访问接口
                UnitChanged(JsonConvert.SerializeObject(bDs));
            }
            if(string.IsNullOrEmpty(messstr))
            {
                //从沃比系统查一下，如果成功了就把所有数据展示出来
                DataTable table = GetAllUnit();
                //把table转为JSON
                messstr = JsonConvert.SerializeObject(table);
            }
            
            return messstr;
        }
        /// <summary>
        /// 云星空计量单位变动反向同步到沃比系统
        /// </summary>
        /// <param name="data">List<BD_UNIT></param>
        /// <returns></returns>
        [HttpGet]
        [Route("UnitChanged")]
        public BreakData UnitChanged(string data)
        {
            BreakData breakData = new BreakData() { Status = false };
            string reason=string.Empty;
            List<BD_UNIT> listunit = _shareController.DataConvertClass<BD_UNIT>(data, ref reason);
            if(listunit == null) {
                breakData.Message = reason;
                return breakData; 
            }
            DataTable table = GetAllUnit();
            DataTable newtb = table.Clone();
            StringBuilder stringBuilder = new StringBuilder();  //更新SQL
            //包裹一个可能产生错误的代码块，以防止将错误返回给了Cloud
            try
            {
                //对比数据，产生增加、更新操作
                if (table.Rows.Count > 0)
                {
                    foreach (BD_UNIT uNIT in listunit)
                    {
                        int id = uNIT.FUNITID;
                        DataRow[] rows = table.Select(string.Format("FUnitID={0}", id));
                        if (rows.Length > 0)
                        {
                            string usql = UpdateDataRow_Unit(uNIT, rows.FirstOrDefault()!);
                            if (!string.IsNullOrEmpty(usql)) { stringBuilder.Append(usql); }
                        }
                        else
                        {
                            AddDataRow_Unit(uNIT, newtb);
                        }
                    }
                }
                else//全是新增
                {
                    foreach (BD_UNIT unit in listunit)
                    {
                        AddDataRow_Unit(unit, newtb);
                    }
                }
                if (newtb != null) { _kdsqlhelper.InsertBill(newtb, "kdCloud_BD_UNIT", ref reason, false); }
                if (string.IsNullOrEmpty(reason))
                {
                    //确保，就算没法有新行，也会执行
                    if (stringBuilder.Length > 0) { _kdsqlhelper.ExecuteNonQueryAsync(stringBuilder.ToString(), CommandType.Text, null, ref reason, false); }
                }
                if (string.IsNullOrEmpty(reason))
                {
                    //清除缓存
                    CacheHelper.Remove("BD_UNIT");
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    breakData.Status = true;
                }
            }
            catch (Exception ex)
            {
                reason=ex.Message;
                //写入错误日志
                _shareController._logger(-1, "UnitChanged", reason, data);
                //throw;
            }
            //不需要返回数据包
            breakData.Message = reason;
            return breakData;
        }
        private DataTable GetAllUnit()
        {
            DataTable table =new DataTable();
            string sql = "SELECT * FROM kdCloud_BD_UNIT";
            string reason = string.Empty;
            DataSet dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, null, ref reason);
            if (dataSet != null)
            {
                if (dataSet.Tables.Count > 0)
                {
                    table = dataSet.Tables[0];
                }
            }
            return table;
        }
        private void AddUnitCache()
        {
            DataTable table = CacheHelper.GetCache<DataTable>("BD_UNIT");
            if (table == null)
            {
                string sql = "SELECT * FROM kdCloud_BD_UNIT WHERE FDocumentStatus=@C AND FForbidStatus=@A";
                SqlParameter[] sqlParameters = new SqlParameter[]
                {
                new SqlParameter("@C","C"),
                new SqlParameter("@A","A")
                };
                string reason = string.Empty;
                DataSet dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, sqlParameters, ref reason);
                if (dataSet != null)
                {
                    if (dataSet.Tables.Count > 0)
                    {
                        table = dataSet.Tables[0];
                       CacheHelper.Set_AbsluteExpire("BD_UNIT", table);
                    }
                }
            }

        }
        /// <summary>
        /// 从沃比数据库取出计量单位，并封装为List<BD_UNIT>
        /// </summary>
        /// <returns></returns>
        private List<BD_UNIT> GetUnit()
        {
            List<BD_UNIT> list = new List<BD_UNIT>();
            string sql = "SELECT * FROM kdCloud_BD_UNIT WHERE FDocumentStatus=@C AND FForbidStatus=@A";
            SqlParameter[] sqlParameters = new SqlParameter[]
            {
                new SqlParameter("@C","C"),
                new SqlParameter("@A","A")
            };
            DataTable dataTable;
            string reason = string.Empty;
            DataSet dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, sqlParameters, ref reason);
            if (dataSet != null)
            {
                if (dataSet.Tables.Count > 0)
                {
                    dataTable = dataSet.Tables[0];
                    list=_shareController.GetClassList<BD_UNIT>(dataTable); 
                }
            }
            return list;
        }
        /// <summary>
        /// MES下达日计划后，将工单号提交给沃比
        /// </summary>
        /// <param name="DocType">接口类型</param>
        /// <param name="data">工单</param>
        /// <returns></returns>
        [HttpPost]
        [Route("UpdatePRDMO")]
        public async Task<string> UpdatePRDMO(string DocType, string data)
        {
            //这是测试代码，不管传来什么都替换


            BreakData breakData = new BreakData() { Status = false };
            string reason = string.Empty;
            //包裹一个可能产生错误的代码块
            try
            {
                List<PRDMO> mos = _shareController.DataConvertClass<PRDMO>(data, ref reason);
                if (mos == null)
                {
                    breakData.Message = reason;
                    return JsonConvert.SerializeObject(breakData);
                }
                //准备校验星空是否有这些数据
                string fieldkeys = "FBillNo,FID,FTreeEntity_FEntryID,FTreeEntity_FSeq";
                System.Collections.ArrayList filterstr = new System.Collections.ArrayList();
                //组装云星空查询
                CloudBillQueryJson queryJson = new CloudBillQueryJson
                {
                    FilterString = string.Format("({0})",string.Join(") or (", filterstr.ToArray())),
                    FieldKeys = fieldkeys,
                    FormId = "PRD_MO"
                };
                if (!_KdhttpClient.Islogin)
                {
                    await _KdhttpClient.LoginErp();
                }
                //从云星空查询
                string jsonstr = JsonConvert.SerializeObject(queryJson);
                List<object> Parameters = new List<object>();
                Parameters.Add(jsonstr);
                _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
                _KdhttpClient.myurl = LocalStaticRequest.tokenurl + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc";
                string result = await _KdhttpClient.AsyncClientRequest();
                //如果访问正常
                if (_KdhttpClient.CloudExecuteQueryStatus(result, ref reason))
                {
                    DataTable table = _shareController.JsonConvertDatatable("FBillNo,FID,FEntryID,FSeq", result,ref reason);
                    if(table != null)
                    {
                        //产生新的日计划记录
                        List<LockPRD_MO> locks = (from a in table.AsEnumerable()
                                                 select new LockPRD_MO
                                                 {
                                                     ERP_MO = a.Field<string>("FBillNo")!,
                                                     MO_SEQ=a.Field<int>("FTreeEntity_FSeq"),
                                                     MOID=a.Field<int>("FID"),
                                                     MOEntryID = a.Field<int>("FEntryID"),
                                                     TRX_DATE=DateTime.Now
                                                 }).ToList();

                        //写入沃比系统
                        _context.r_LockPRD_MO!.AddRange(locks);
                        int q = await _context.SaveChangesAsync();
                        if (q > 0)
                        {
                            breakData.Status = true;
                            breakData.DataSet = locks;
                        }
                    }
                    else
                    {
                        breakData.Status = false;
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Status = false;
                    breakData.Message = reason;
                }

                //如果有错误发生，就会跑到catch中去...
            }
            catch (Exception ex)
            {
                reason = ex.Message;
                breakData.Message = reason;
                //同时写入日志
                _shareController._logger(-1, DocType, reason, data);
                //throw;
            }
            return JsonConvert.SerializeObject(breakData);
        }
        /// <summary>
        /// 获取MES系统日计划工单
        /// </summary>
        /// <param name="data">LockPRD_MO列表的JSON字符串</param>
        /// <returns></returns>
        [HttpGet]
        [Route("GetLockMOsAsync")]
        public async Task<string> GetLockMOsAsync(string data)
        {
            BreakData breakData=new BreakData() { Status=false };
            string reason = string.Empty;
            //包裹一个可能产生错误的代码块，以防止将错误返回给了Cloud
            try
            {
                List<LockPRD_MO> mos = _shareController.DataConvertClass<LockPRD_MO>(data, ref reason);
                if (mos == null)
                {
                    breakData.Message = reason;
                    return JsonConvert.SerializeObject(breakData);
                }
                //EF处理起来更慢，使用直接SQL
                System.Collections.ArrayList stringBuilder = new System.Collections.ArrayList();
                foreach(LockPRD_MO po in mos)
                {
                    string number = po.ERP_MO;
                    int seq = po.MO_SEQ;
                    int moid = po.MOID;
                    int moentryid = po.MOEntryID;
                    System.Collections.ArrayList arrayList = new System.Collections.ArrayList();
                    if (number != "") { arrayList.Add(string.Format("ERP_MO='{0}'", number)); }
                    if (seq != 0) { arrayList.Add(string.Format("MO_SEQ={0}", seq)); }
                    if (moid != 0) { arrayList.Add(string.Format("MOID={0}", moid)); }
                    if (moentryid != 0) { arrayList.Add(string.Format("MOEntryID={0}", moentryid)); }
                    stringBuilder.Add(string.Join(" AND ", arrayList.ToArray()));
                }
                string sql =string.Format(@"SELECT * FROM r_LockPRD_MO WHERE ({0})",string.Join(") OR (", stringBuilder.ToArray()));
                DataSet dataSet =_kdsqlhelper.GetDataSet(CommandType.Text,sql,null,ref reason,false);
                if (dataSet == null) { return JsonConvert.SerializeObject(breakData); }
                if(dataSet.Tables.Count==0) { return JsonConvert.SerializeObject(breakData); }
                if (dataSet.Tables[0].Rows.Count == 0) { return JsonConvert.SerializeObject(breakData); }
                
                List<LockPRD_MO> locks = (from a in dataSet.Tables[0].AsEnumerable()
                                     select new LockPRD_MO
                                     {
                                         FID= a.Field<int>("FID"),
                                         ERP_MO = a.Field<string>("ERP_MO")!,
                                         MO_SEQ = a.Field<int>("MO_SEQ"),
                                         MOID = a.Field<int>("MOID"),
                                         MOEntryID = a.Field<int>("MOEntryID"),
                                         TRX_DATE = a.Field<DateTime>("TRX_DATE")
                                     }).ToList();
                breakData.DataSet = locks;
                breakData.Status = true;
            }
            catch (Exception ex)
            {
                reason =ex.Message;
                breakData.Message = reason;
                //同时写入日志
                _shareController._logger(-1, "GetLockMOsAsync", reason,data);
            }

            //测试序列化与反序列化
            string result = JsonConvert.SerializeObject(breakData);
            return result;
        }
        /// <summary>
        /// 测试R104：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("test_PostAsync_R104")]
        public async Task<string> test_PostR014Async()
        {
            List<R014> testpos = new List<R014>();
            testpos.Add(new R014() { QUEUE_ID = "1", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "1", MTRL_ID = "KP-BK-005", QUANTITY = "1", REMARK = "测试第一行为1 Pcs", ERP_LOTNO = "", STORELOC_ID = "001" });
            testpos.Add(new R014() { QUEUE_ID = "2", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "2", MTRL_ID = "KP-PM-001", QUANTITY = "2", REMARK = "测试第二行为2 Pcs", ERP_LOTNO = "", STORELOC_ID = "002" });
            testpos.Add(new R014() { QUEUE_ID = "3", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "3", MTRL_ID = "KD-LOGO-00", QUANTITY = "3", REMARK = "测试第三行为3 Pcs", ERP_LOTNO = "", STORELOC_ID = "003" });
            testpos.Add(new R014() { QUEUE_ID = "4", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "4", MTRL_ID = "KP-SX-001", QUANTITY = "4", REMARK = "测试第四行为4 Pcs", ERP_LOTNO = "", STORELOC_ID = "001" });
            testpos.Add(new R014() { QUEUE_ID = "5", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "5", MTRL_ID = "KD-LOGO-00", QUANTITY = "5", REMARK = "测试第三行为5 Pcs", ERP_LOTNO = "", STORELOC_ID = "002" });
            testpos.Add(new R014() { QUEUE_ID = "6", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK007", ERP_MO = "PPBOM00000054", MO_SEQ = "6", MTRL_ID = "KP-SX-001", QUANTITY = "6", REMARK = "测试第四行为6 Pcs", ERP_LOTNO = "", STORELOC_ID = "003" });
            testpos.Add(new R014() { QUEUE_ID = "7", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "PPBOM00000051", MO_SEQ = "1", MTRL_ID = "S1.03.004", QUANTITY = "1", REMARK = "测试多张单据一起下推", ERP_LOTNO = "", STORELOC_ID = "" });
            testpos.Add(new R014() { QUEUE_ID = "8", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "PPBOM00000051", MO_SEQ = "2", MTRL_ID = "S1.03.005", QUANTITY = "2", REMARK = "测试多张单据一起下推", ERP_LOTNO = "", STORELOC_ID = "" });
            testpos.Add(new R014() { QUEUE_ID = "9", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "PPBOM00000051", MO_SEQ = "3", MTRL_ID = "S1.03.006", QUANTITY = "1", REMARK = "测试多张单据一起下推", ERP_LOTNO = "", STORELOC_ID = "" });

            string DocType = "R014";
            //string data = JsonConvert.SerializeObject(testpos);
            RequestParm parm = new RequestParm() { DocType = DocType, data = testpos };
            return await PostAsync(parm);
        }
        /// <summary>
        /// 测试R102：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("test_PostAsync_R102")]
        public async Task<string> test_PostR102Async()
        {
            List<R102> testpos = new List<R102>();
            testpos.Add(new R102() { QUEUE_ID = "1", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "MO000036", MO_SEQ = "1", MTRL_ID = "1.02.001.0002", QUANTITY = "1", REMARK = "测试第一行为1 Pcs",  STORELOC_ID = "001", ERP_LOTNO = "" });

            string DocType = "R102";
            //string data = JsonConvert.SerializeObject(testpos);
            RequestParm parm = new RequestParm() { DocType = DocType, data = testpos };
            return await PostAsync(parm);
        }
        /// <summary>
        /// 测试R014_1：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        //[HttpPost]
        //[Route("test_PostAsync_R014_1")]
        //public async Task<string> test_PostR014_1Async()
        //{
        //    List<R014_1> testpos = new List<R014_1>();
        //    testpos.Add(new R014_1() { QUEUE_ID = "1", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "MO000036", MO_SEQ = "1", MTRL_ID = "1.02.001.0002", QUANTITY = "1", REMARK = "测试第一行为1 Pcs", STORELOC_ID = "001", ERP_LOTNO = "" });

        //    string DocType = "R014_1";
        //    string data = JsonConvert.SerializeObject(testpos);
        //    return await PostAsync(DocType, data);
        //}
        /// <summary>
        /// 测试R019_1：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        //[HttpPost]
        //[Route("test_PostAsync_R019_1")]
        //public async Task<string> test_PostR019_1Async()
        //{
        //    List<R019_1> testpos = new List<R019_1>();
        //    testpos.Add(new R019_1() { QUEUE_ID = "1", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "CK001", ERP_MO = "MO000036", MO_SEQ = "1", MTRL_ID = "1.02.001.0002", QUANTITY = "1", REMARK = "测试第一行为1 Pcs", STORELOC_ID = "001", ERP_LOTNO = "" });

        //    string DocType = "R102";
        //    string data = JsonConvert.SerializeObject(testpos);
        //    return await PostAsync(DocType, data);
        //}
        /// <summary>
        /// 测试R170C：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("test_PostAsync_R170C")]
        public async Task<string> test_PostR170CAsync()
        {
            List<R170C> testpos = new List<R170C>();
            testpos.Add(new R170C() { QUEUE_ID = "0", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "001", SUP_ID = "VEN00003", PO_ID = "CGDD000025", PO_SEQ = "1", MTRL_ID = "4..01", QUANTITY = "1", REMARK = "测试第一行为1 Pcs", ERP_LOTNO = "", STORELOC_ID = "" });
            testpos.Add(new R170C() { QUEUE_ID = "1", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "001", SUP_ID = "VEN00003", PO_ID = "CGDD000025", PO_SEQ = "1", MTRL_ID = "4..01", QUANTITY = "2", REMARK = "测试第二行为2 Pcs", ERP_LOTNO = "", STORELOC_ID = "" });
            testpos.Add(new R170C() { QUEUE_ID = "2", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "001", SUP_ID = "VEN00003", PO_ID = "CGDD000025", PO_SEQ = "1", MTRL_ID = "4..01", QUANTITY = "3", REMARK = "测试第三行为3 Pcs", ERP_LOTNO = "", STORELOC_ID = "" });
            testpos.Add(new R170C() { QUEUE_ID = "3", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "001", SUP_ID = "VEN00003", PO_ID = "CGDD000025", PO_SEQ = "1", MTRL_ID = "4..01", QUANTITY = "4", REMARK = "测试第四行为4 Pcs", ERP_LOTNO = "", STORELOC_ID = "" });

            string DocType = "R170C";
            //string data = JsonConvert.SerializeObject(testpos);
            RequestParm parm = new RequestParm() { DocType = DocType, data = testpos };
            return await PostAsync(parm);
        }
        /// <summary>
        /// 测试RO-VMI：批量提交MES单据到云星空，保存、提交、审核一起完成
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("test_PostAsync_RO-VMI")]
        public async Task<string> test_PostROVMIAsync()
        {
            List<R170C> testpos = new List<R170C>();
            testpos.Add(new R170C() { QUEUE_ID = "0", TRX_DATE = DateTime.Now.ToShortDateString(), STORE_ID = "001", SUP_ID = "VEN00003", PO_ID = "CGDD000025", PO_SEQ = "2", MTRL_ID = "4..01", QUANTITY = "1", REMARK = "测试VMI赠品入库", ERP_LOTNO = "", STORELOC_ID = "" });

            string DocType = "RO-VMI";
            //string data = JsonConvert.SerializeObject(testpos);
            RequestParm parm = new RequestParm() { DocType = DocType, data = testpos };
            return await PostAsync(parm);
        }
        /// <summary>
        /// 从ERP中查询数据
        /// </summary>
        /// <param name="data">查询条件数据包</param>
        /// <returns></returns>
        [HttpGet]
        [Route("GetERPData")]
        public async Task<string> GeterpdataAsync(string data)
        {
            int fid = await _context.r_FunctionList!.Where(s => s.FUsing && s.FFunctionName == "GetERPData").AsNoTracking().Select(s => s.FID).FirstOrDefaultAsync();
            ////优先从内存访问
            //if (queryJsons == null || queryJsons.Count == 0)
            //{
            //    queryJsons = await GetCloudBillQueriesAsync();
            //}

            BreakData breakData = new BreakData();
            string result = string.Empty;
            string reason = string.Empty;
            try
            {
                if (!string.IsNullOrEmpty(data))
                {
                    GetErpParameters erpParameters = JsonConvert.DeserializeObject<GetErpParameters>(data)!;
                    if (erpParameters != null)
                    {
                        string DocType = erpParameters.DocType;
                        if (!string.IsNullOrEmpty(DocType))
                        {
                            var querjson = _context.r_CloudBillQuery!
                                .Include(s => s.GetFormID).ThenInclude(s => s.functions)
                                .Where(s => s.GetFormID.FFunctionID == fid && s.GetFormID.FDocType == DocType)
                                .AsNoTracking();
                            if (querjson.Any())
                            {
                                CloudBillQuery billquery = querjson.FirstOrDefault()!;
                                result = await PugAsync(erpParameters.KeyValues, billquery);
                                //判断是对还是错
                                if (_KdhttpClient.CloudExecuteQueryStatus(result, ref reason))
                                {
                                    object ps = new object();
                                    //转换为客户端需要的格式
                                    switch (DocType)
                                    {
                                        case "PO":
                                            ps = _shareController.GetNewObj<PO>(fid, DocType, result, ref reason);
                                            break;
                                        case "XCL":
                                            ps = _shareController.GetNewObj<XCL>(fid, DocType, result, ref reason);
                                            break;
                                    }
                                    if (reason == "")
                                    {
                                        breakData.Status = true;
                                        breakData.DataSet = ps;
                                    }
                                    else
                                    {
                                        breakData.Status = false;
                                        breakData.Message = reason;
                                    }
                                }
                                else
                                {
                                    breakData.Status = false;
                                    breakData.Message = reason;
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "CloudBillQuery还未配置";
                            }
                        }
                        else
                        {
                            breakData.Status = false;
                            breakData.Message = "提供的参数中必须包含DocType";
                        }
                    }
                }
                else
                {
                    breakData.Status = false;
                    breakData.Message = "不接受空的数据包";
                }
            }
            catch (Exception e)
            {
                breakData.Status = false;
                breakData.Message = e.Message;
                //throw;
                WritLog(e.Message);
            }
            return JsonConvert.SerializeObject(breakData);
        }
        /// <summary>
        /// 匹配合适的参数，从金蝶Cloud中查询数据
        /// </summary>
        /// <param name="pairs">输入参数</param>
        /// <param name="billquery"></param>
        /// <returns></returns>
        private async Task<string> PugAsync(Dictionary<string, object> pairs, CloudBillQuery billquery)
        {
                string filterstr = billquery.FFiledString;
            //解析KeyValues
            string FilterString = GetErpDataPar(billquery.GetFormID.FFunctionID, pairs, billquery.GetFormID.FDocType, filterstr);
            CloudBillQueryJson queryJson = new CloudBillQueryJson
            {
                FilterString = FilterString,
                FieldKeys = billquery.FFieldKeys,
                FormId = billquery.GetFormID.FDBName,
                Limit = billquery.FLimit,
                OrderString = billquery.FOrderString,
                StartRow = billquery.FStartRow,
                SubSystemId = billquery.FSubSystemID,
                TopRowCount = billquery.FTopRowCount
            };
            if (!_KdhttpClient.Islogin)
            {
                await _KdhttpClient.LoginErp();
            }
            //从云星空查询
            string jsonstr = JsonConvert.SerializeObject(queryJson);
            List<object> Parameters = new List<object>();
            Parameters.Add(jsonstr);
            _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
            _KdhttpClient.myurl = billquery.GetFormID.functions.FUrl;
            //result =  _KdhttpClient.AsyncRequest();
            return await _KdhttpClient.AsyncClientRequest();
        }

        /// <summary>
        /// MES传过来的参数转义
        /// </summary>
        /// <param name="fid">FunctionID</param>
        /// <param name="inputKeyValues">输入的参数和值</param>
        /// <param name="DocType">查询类别</param>
        /// <param name="filterstr"></param>
        /// <returns></returns>
        private string GetErpDataPar(int fid, Dictionary<string, object> inputKeyValues, string DocType, string filterstr)
        {
            string result = filterstr;
            //根据SelectJoinID获取参数列表
            var sj = _context.r_SelectJoinID!.Where(s => s.FFunctionID == fid && s.FDocType.Equals(DocType)).AsNoTracking();
            if (sj != null)
            {
                foreach (var s in sj)
                {
                    string pars = s.FOptcode;
                    string[] strings = pars.Split('|');
                    if (strings.Length > 0)
                    {
                        foreach (string s2 in strings)
                        {
                            string[] strings1 = s2.Split('=');
                            if (strings1.Length == 2)
                            {
                                result = result.Replace(strings1[0], inputKeyValues[strings1[0]].ToString());
                                //result += string.IsNullOrEmpty(result) ? strings1[1] + "='" + inputKeyValues[strings1[0]] + "'" : 
                                //    " AND " + strings1[1] + "='" + inputKeyValues[strings1[0]] + "'";
                            }
                            else
                            {
                                result = result.Replace(strings1[0], inputKeyValues[strings1[0]].ToString());
                                //result += string.IsNullOrEmpty(result) ? s2 + "='" + inputKeyValues[s2] + "'":
                                //    " AND " + s2 + "='" + inputKeyValues[s2] + "'";
                            }
                        }
                    }

                }
            }
            return result;
        }
        /// <summary>
        /// 批量提交单据输入参数校验
        /// </summary>
        /// <param name="DocType">接口类型,云星空的FormId,传入时不必区分大小写</param>
        /// <param name="data">单据数据包</param>
        /// <param name="reason">当有错误时返回的消息</param>
        /// <returns></returns>
        private bool PostAsyncCheck(string DocType, string data,ref string reason)
        {
            reason = "";
            bool result = true;
            if (!_context.r_DataSaveBatch!.Any())
            {
                result = false;
                reason += "未配置JSON格式数据";
            }
            if (string.IsNullOrEmpty(DocType))
            {
                result = false;
                reason += reason=="" ? "必须指定接口类型" : "\n" + "必须指定接口类型";
            }
            if (string.IsNullOrEmpty(data))
            {
                result = false;
                reason += reason == "" ? "不接受空的数据包" : "\n" + "不接受空的数据包";
            }
            return result;
        }
        /// <summary>
        /// 根据接口类型，返回关于它的定义项
        /// </summary>
        /// <param name="DocType">接口类型</param>
        /// <returns></returns>
        private async Task<List<FormIDType>> GetAllFormIDTypeAsync(string DocType)
        {
            List<FormIDType> result = await _context.r_FormIDType!.Include(s => s.functions)
                    .Where(f => f.functions.FUsing)
                    .Where(s => s.FUsing && s.FDocType.Equals(DocType))
                    .AsNoTracking().ToListAsync(); ;
            return result;
        }
        /// <summary>
        /// 单个单据的保存接口
        /// </summary>
        /// <typeparam name="T">要提交保存的类</typeparam>
        /// <param name="formid">云星空的FormId</param>
        /// <param name="inputdata">整理好的表单</param>
        /// <returns></returns>
        private async Task<BreakData> SaveAsync<T>(string formid,T inputdata) where T : class
        {
            BreakData data = new BreakData() { Status = false };
            string messstr = string.Empty;
            DataSaveJson batchJson = new DataSaveJson { Model = inputdata };
            if (!_KdhttpClient.Islogin)
            {
                await _KdhttpClient.LoginErp();
            }
            //从云星空查询
            string jsonstr = JsonConvert.SerializeObject(batchJson);
            List<object> Parameters = new List<object>() { formid, jsonstr };
            _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
            //_KdhttpClient.myurl = "http://i.enpower.com:8600/k3cloud/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc";
            //string result = _KdhttpClient.AsyncRequest();
            string result = await _KdhttpClient.AsyncClientRequest();
            //如果访问正常
            data.Status = _shareController.CloudExecuteSaveStatus(result, ref messstr);
            data.Message = messstr;
            return data;
        }
        /// <summary>
        /// 批量提交给Cloud的单据，不会自动提交与审核
        /// </summary>
        /// <typeparam name="T">泛型，实体类</typeparam>
        /// <param name="batchObj">批量提交参数</param>
        /// <param name="inputdata">泛型，需要提交的实体类</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchAsync<T>(DataSaveBatch? batchObj,string url,string formid,List<T> inputdata) where T : class
        {
            BreakData data = new BreakData() { Status = false };
            string messstr = string.Empty;
            if (batchObj != null)
            {
                string breakfileds = batchObj.FNeedReturnFields;
                string updatefields = batchObj.FNeedUpDateFields;
                DataSaveBatchJson batchJson = new DataSaveBatchJson()
                {
                    Model = inputdata,
                    IgnoreInterationFlag = batchObj.FIgnoreInterationFlag,
                    InterationFlags = batchObj.FInterationFlags,
                    IsAutoAdjustField = batchObj.FIsAutoAdjustField,
                    //IsAutoSubmitAndAudit = batchObj.FIsAutoSubmitAndAudit,
                    IsDeleteEntry = batchObj.FIsDeleteEntry,
                    IsEntryBatchFill = batchObj.FIsEntryBatchFill,
                    IsVerifyBaseDataField = batchObj.FIsVerifyBaseDataField,
                    SubSystemId = batchObj.FSubSystemId,
                    BatchCount = batchObj.FBatchCount,
                    NeedReturnFields = breakfileds=="" ? null : breakfileds.Split(","),
                    NeedUpDateFields = updatefields=="" ? null : updatefields.Split(","),
                    NumberSearch = batchObj.FNumberSearch,
                    ValidateFlag = batchObj.FValidateFlag
                };
                if (!_KdhttpClient.Islogin)
                {
                    await _KdhttpClient.LoginErp();
                }
                //从云星空查询
                string jsonstr = JsonConvert.SerializeObject(batchJson);
                List<object> Parameters = new List<object>() { formid, jsonstr };
                _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
                _KdhttpClient.myurl = url;
                //string result = _KdhttpClient.AsyncRequest();
                string result = await _KdhttpClient.AsyncClientRequest();
                //如果访问正常
                List<Dictionary<string, string>> billnos = new List<Dictionary<string, string>>();
                data.Status = _shareController.CloudExecuteBatchSaveStatus(result, breakfileds, ref billnos);
                if (data.Status)
                {
                    data.DataSet = billnos;
                }
                else
                {
                    messstr = billnos[0].FirstOrDefault().Value;
                }
            }
            else
            {
                messstr = "请检查批量提交配置...";
            }
            data.Message = messstr;
            return data;
        }
        /// <summary>
        /// 批量提交已保存的单据
        /// </summary>
        /// <param name="billlist">单据编号列表</param>
        /// <param name="formid">Cloud的FormId</param>
        /// <param name="submiturl"></param>
        /// <returns></returns>
        private async Task<BreakData> SubmitCloudAsync(List<string> billlist,string formid,string submiturl)
        {
            BreakData data = new BreakData() { Status = false };
            string messstr = string.Empty;
            SubmitJson submitJson = new SubmitJson() { Numbers=billlist.ToArray()};
            if (!_KdhttpClient.Islogin)
            {
                await _KdhttpClient.LoginErp();
            }
            //从云星空查询
            string jsonstr = JsonConvert.SerializeObject(submitJson);
            List<object> Parameters = new List<object>() { formid, jsonstr };
            _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
            _KdhttpClient.myurl = submiturl;
            //string result = _KdhttpClient.AsyncRequest();
            string result = await _KdhttpClient.AsyncClientRequest();
            //如果访问正常
            List<string> billnos = new List<string>();
            data.Status = _shareController.CloudExecuteSaveStatus(result, ref messstr);
            if (data.Status)
            {
                data.DataSet = billnos;    //此时为单据编号
            }
            else
            {
                messstr = billnos[0];
            }
            return data;
        }
        /// <summary>
        /// 批量审核已提交的单据
        /// </summary>
        /// <param name="billlist">单据编号列表</param>
        /// <param name="formid">Cloud的FormId</param>
        /// <param name="aduiturl">审核的Url地址</param>
        /// <returns></returns>
        private async Task<BreakData> AuditCloudAsync(List<string> billlist, string formid, string aduiturl)
        {
            BreakData data = new BreakData() { Status = false };
            string messstr = string.Empty;
            AuditJson submitJson = new AuditJson() { Numbers = billlist.ToArray() };
            if (!_KdhttpClient.Islogin)
            {
                await _KdhttpClient.LoginErp();
            }
            //从云星空查询
            string jsonstr = JsonConvert.SerializeObject(submitJson);
            List<object> Parameters = new List<object>() { formid, jsonstr };
            _KdhttpClient.content = JsonConvert.SerializeObject(Parameters);
            _KdhttpClient.myurl = aduiturl;
            //string result = _KdhttpClient.AsyncRequest();
            string result = await _KdhttpClient.AsyncClientRequest();
            //如果访问正常
            List<string> billnos = new List<string>();
            data.Status = _shareController.CloudExecuteSaveStatus(result, ref messstr);
            if (data.Status)
            {
                data.DataSet = billlist;     //此时为单据编号
            }
            else
            {
                messstr = billnos[0];
            }
            return data;
        }

        /// <summary>
        /// 更新普通采购订单，以目标表的单据类型编码命名
        /// </summary>
        /// <param name="inStocks">外购入库明细</param>
        /// <param name="url"></param>
        /// <returns></returns>
        private async Task<BreakData> UpdateCGDD01_SYSAsync(List<STK_InStock> inStocks,string url)
        {
            BreakData breakData = new BreakData() { Status = false };
            var entries = from a in inStocks
                          select a.FInStockEntry;
            List<STK_InStock.InStockEntry> instockentries = new List<STK_InStock.InStockEntry>();
            foreach (var entry in entries)
            {
                foreach (var t in entry)
                {
                    instockentries.Add(t);
                }
            }
            //取出已入库汇总、未入库汇总
            var polist = from a in instockentries
                         group a by new {
                             A = a.FPOOrderNo,
                             B = a.FPOORDERENTRYID,
                             C=a.FInStockEntry_Link!.FirstOrDefault()!.FInStockEntry_Link_FSBillId,
                             D=a.FUnitID,
                             E=a.FRemainInStockUnitId,
                             F=a.FMaterialId,
                             G=a.FPriceUnitID
                         }
                       into b
                         select new
                         {
                             OrderNo=b.Key.A,
                             OrderEntryID = b.Key.B,
                             SBillId=b.Key.C,
                             UnitID=b.Key.D,
                             RemainInStockUnitId=b.Key.E,
                             MaterialId =b.Key.F,
                             PriceUnitID=b.Key.G,
                             FMustQty = b.Sum(s => s.FMustQty),
                             FRealQty = b.Sum(s => s.FRealQty)
                         };
            if (instockentries.Count > 0)
            {
                List<PUR_PurchaseOrder> purchaseorders = new List<PUR_PurchaseOrder>();
                List<string> pogroup = polist.Select(s => s.OrderNo).Distinct().ToList();
                foreach(string po in pogroup)
                {
                    var poentry =polist.Where(s=>s.OrderNo==po).ToList();
                    //为采购订单赋值
                    PUR_PurchaseOrder order = new PUR_PurchaseOrder()
                    {
                        FBillNo = po,
                        FID=int.Parse(poentry.FirstOrDefault()!.SBillId)
                    };
                    List<PUR_PurchaseOrder.POOrderEntry> entrylist = new List<PUR_PurchaseOrder.POOrderEntry>();
                    foreach (var entry in poentry)
                    {
                        PUR_PurchaseOrder.POOrderEntry orderEntry = new PUR_PurchaseOrder.POOrderEntry()
                        {
                            FEntryID = int.Parse(entry.OrderEntryID),
                            FMaterialId = entry.MaterialId,
                            FPriceUnitID = entry.PriceUnitID,
                            FStockUnitID = entry.UnitID,
                            FUnitID = entry.RemainInStockUnitId,
                            FStockInQty= entry.FMustQty + entry.FRealQty,
                            FRemainStockINQty = entry.FMustQty - entry.FRealQty,
                            FEntryDeliveryPlan = new List<PUR_PurchaseOrder.POOrderEntry.EntryDeliveryPlan>
                            {
                                new PUR_PurchaseOrder.POOrderEntry.EntryDeliveryPlan()
                                {
                                    FBaseDeliCommitQty=entry.FMustQty + entry.FRealQty ,
                                    FBaseDeliRemainQty=entry.FMustQty - entry.FRealQty ,
                                    FDeliCommitQty=entry.FMustQty + entry.FRealQty ,
                                    FDeliRemainQty=entry.FMustQty - entry.FRealQty
                                }
                            }
                        };
                        entrylist.Add(orderEntry);
                        order.FPOOrderEntry = entrylist;
                    }
                    purchaseorders.Add(order);
                }
                if(purchaseorders.Count > 0)
                {
                    string formid = "PUR_PurchaseOrder";
                    //推送数据
                    DataSaveBatch? dataSave = new DataSaveBatch()
                    {
                        FNeedUpDateFields = "FStockInQty,FRemainStockINQty,FBaseDeliCommitQty,FBaseDeliRemainQty,FDeliCommitQty,FDeliRemainQty",
                    };
                    //调用批量保存功能
                    breakData = await SaveBatchAsync(dataSave, url, formid, purchaseorders);
                }
            }
            else
            {
                breakData.Message="没有需要反写采购订单";
            }
            return breakData;
        }
        /// <summary>
        /// 批量提交MES单据到云星空
        /// </summary>
        /// <param name="parm">RequestParm</param>
        [HttpPost]
        [Route("DataSave_Batch")]
        public async Task<string> PostAsync([FromBody] RequestParm parm)
        {
            BreakData breakData = new BreakData() { Status = false };
            if(parm == null)
            {
                breakData.Message = "输入的格式不正确";
                goto E;
            }
            string result = string.Empty;
            string reason = string.Empty;
            string DocType = parm.DocType;
            if (string.IsNullOrEmpty(parm.data.ToString()) || string.IsNullOrEmpty(DocType))
            {
                breakData.Message = "传入的参数不正确";
                goto E;
            }
            JArray iResultStr = (JArray)JsonConvert.DeserializeObject(parm.data.ToString()!);
            string data = JsonConvert.SerializeObject(iResultStr);
            if (!PostAsyncCheck(DocType,data,ref reason))
            {
                breakData.Message = reason;
                goto E;
            }

            try
            {
                //查FFunctionID、查FormId
                List<FormIDType> fm_all =await GetAllFormIDTypeAsync(DocType);
                if (!fm_all.Any())
                {
                    breakData.Message = "无法匹配要传入的对象，请检查r_FormIDType配置是否正确";
                    goto E;
                }
                var fm_post = fm_all.Where(f => f.functions.FUsing && f.FActionName == "PostAsync");
                if (!fm_post.Any())
                {
                    breakData.Message = "没有PostAsync的配置项，请检查r_FormIDType配置是否正确";
                    goto E;
                }
                //注意：这里要用的是提交参数
                if (_context.r_DataSaveBatch!.Include(s=>s.GetForm).Any(s => s.GetForm.FFunctionID == fm_post!.FirstOrDefault()!.FFunctionID && s.FDocTypeID == fm_post.FirstOrDefault()!.FID))
                {
                    //如果有子查询...
                    //是否存在子查询都要单独写方法...
                    var fm_child = fm_all.Where(f => f.functions.FUsing && f.FActionName == "ChiledSelect");
                    if (fm_child.Any())
                    {
                        int fchildid = fm_child.FirstOrDefault()!.FFunctionID;
                        int fchildmid = fm_child.FirstOrDefault()!.FID;
                        //首先，将data转为DataTable待用于内码转换
                        DataTable dataTable = await _shareController.GetInputDataTable(fchildid, fm_child.FirstOrDefault()!.FDBName, data);
                        if (dataTable != null)
                        {
                            //查找并配置Model,根据字段转换规则，匹配对应的类
                            string kdformid = fm_post!.FirstOrDefault()!.FDBName;
                            switch (kdformid.ToUpper())
                            {
                                //源单为采购订单的入库
                                case "STK_INSTOCK":
                                    breakData =await SaveBatchInStockAsync(dataTable, 
                                        fm_post!.FirstOrDefault()!.FFunctionID, 
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid, 
                                        data);
                                    break;
                                    //普通生产领料
                                case "PRD_PICKMTRL":
                                    breakData=await SaveBatchPickMtrlAsync(dataTable,
                                        fm_post!.FirstOrDefault()!.FFunctionID,
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid,
                                        data);
                                    break;

                                //生产入库单
                                case "PRD_INSTOCK":
                                    breakData = await SaveBatchINSTOCKAsync(dataTable,
                                        fm_post!.FirstOrDefault()!.FFunctionID,
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid,
                                        data);
                                    break;
                                //委外领料单
                                case "SUB_PickMtrl":
                                    breakData = await SaveBatchSUBPickMtrlAsync(dataTable,
                                        fm_post!.FirstOrDefault()!.FFunctionID,
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid,
                                        data);
                                    break;
                                //委外退料单
                                case "SUB_RETURNMTRL":
                                    breakData = await SaveBatchSUBRETURNMTRLAsync(dataTable,

                                        fm_post!.FirstOrDefault()!.FFunctionID,
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid,
                                        data);
                                    break;
                                //生产退料单
                                case "PRD_ReturnMtrl":
                                    breakData = await SaveBatchPRDReturnMtrlAsync(dataTable,
                                        fm_post!.FirstOrDefault()!.FFunctionID,
                                        fm_post.FirstOrDefault()!.FID,
                                        fchildmid,
                                        data);
                                    break;
                            }
                        }
                        else
                        {
                            breakData.Message = "未配置子查询的ClumnConvert";
                            goto E;
                        }
                    }
                    else
                    {
                        //没有子查询的...
                    }
                }
                else
                {
                    breakData.Message = "未配置属于【" + DocType + "】的JSON提交参数";
                    goto E;
                }
            }
            catch (Exception ex)
            {
                breakData.Message = ex.Message;
                WritLog(ex.Message);
            }
        E:
            return JsonConvert.SerializeObject(breakData);
        }


        /// <summary>
        /// MES反推单据或更新单据
        /// </summary>
        /// <param name="DocType">单据类型</param>
        /// <param name="data">单据数据包</param>
        [HttpPost]
        [Route("UpdateErpBill")]
        public string Put(string DocType, string data)
        {
            return DocType + "\n" + data;
        }


        /// <summary>
        /// 将转入data转为云星空需要的类
        /// </summary>
        /// <param name="spacename">命名空间名</param>
        /// <param name="clssname">类名</param>
        /// <param name="data">转入的参数</param>
        /// <param name="reason"></param>
        /// <returns></returns>
        private List<object>? DataConvertClass(string spacename,string clssname, string data,ref string reason)
        {
            reason = "";
            List<object> list = new List<object>();
            //获得Models下所有模型
            var typelist = Assembly.GetExecutingAssembly().GetTypes()
                .Where(s => s.Namespace == spacename)
                .Where(p => p.Name == clssname);
            if (typelist.Any())
            {
                Type? type = typelist.FirstOrDefault();
                if (type != null)
                {
                    try
                    {
                        JArray jArray = (JArray)JsonConvert.DeserializeObject(data)!;
                        //List<object> list = JsonConvert.DeserializeObject<List<object>>(data)!;       //如果直接这样使用，则有些字段不相同的不会报错...
                        foreach (var item in jArray)
                        {
                            if(item != null)
                            {
                                list.Add(item.ToObject(type));
                            }
                        }
                        return list;
                    }
                    catch (Exception ex)
                    {
                        reason= "将转入data转为云星空需要的类时，发生错误：" + ex.Message;
                        //throw;
                    }                    
                }
                {
                    reason = "将转入data转为云星空需要的类时，指定的类型不存在...";
                }
            }
            return list;
        }
        
        /// <summary>
        /// 入库接口与采购订单信息对比验证
        /// </summary>
        /// <param name="mes">MES推过来的数据类</param>
        /// <param name="indata">ERP的采购订单信息</param>
        /// <returns></returns>
        private string PONoInStockQtyCheck(List<R170C> mes,List<PurchaseOrder> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder =new StringBuilder();
            var R170 = from a in mes.AsEnumerable()
                       group a by new { a.PO_ID, a.PO_SEQ } into b
                       select new
                       {
                           PO_ID = b.Key.PO_ID,
                           PO_SEQ = b.Key.PO_SEQ,
                           Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                       };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                     select new { a.PO_ID, a.PO_SEQ }
                  ).Except(
                from b in indata select new { PO_ID = b.FBillNo, PO_SEQ = b.FPOOrderEntry_FSeq }
                );
            if(poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.PO_ID, p.PO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var SR170 = from a in R170
                        join b in indata on new { A = a.PO_ID, B = a.PO_SEQ } equals new { A = b.FBillNo, B = b.FPOOrderEntry_FSeq }
                        where a.Qty > _shareController.DecimalPar(b.FRemainInStockQty)
                        select new
                        {
                            PO_ID = a.PO_ID,
                            PO_SEQ = a.PO_SEQ,
                            Qty = _shareController.DecimalPar(b.FRemainInStockQty) - a.Qty
                        };
            if (SR170 != null)
            {
                foreach (var s in SR170)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超过未入库数{2}。",s.PO_ID,s.PO_SEQ,s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// 生产领料接口与生产用料清单信息对比验证
        /// </summary>
        /// <param name="mes">MES推过来的数据类</param>
        /// <param name="indata">ERP的生产用料清单信息</param>
        /// <returns></returns>
        private string PONoPickMtrlQtyCheck(List<R014> mes, List<PrdPpbomEntry> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder = new StringBuilder();
            var rs = from a in mes.AsEnumerable()
                       group a by new { a.ERP_MO, a.MO_SEQ } into b
                       select new
                       {
                           ERP_NO = b.Key.ERP_MO,
                           ERP_SEQ = b.Key.MO_SEQ,
                           Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                       };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                            select new { a.ERP_MO, a.MO_SEQ }
                  ).Except(
                from b in indata select new { ERP_MO = b.FBillNo, MO_SEQ = b.FEntity_FSeq.ToString() }
                );
            if (poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.ERP_MO, p.MO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var rs_mes = from a in rs
                        join b in indata on new { A = a.ERP_NO, B = a.ERP_SEQ } equals new { A = b.FBillNo, B = b.FEntity_FSeq.ToString() }
                        where a.Qty > (int.Parse(b.FNeedQty2) - int.Parse(b.FPickedQty))
                         select new
                        {
                            ERP_NO = a.ERP_NO,
                            ERP_SEQ = a.ERP_SEQ,
                            Qty = (int.Parse(b.FNeedQty2) - int.Parse(b.FPickedQty) - a.Qty)
                        };
            if (rs_mes != null)
            {
                foreach (var s in rs_mes)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超过未入库数{2}。", s.ERP_NO, s.ERP_SEQ, s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 生产订单接口与生产用入库单信息对比验证
        /// </summary>
        /// <param name="mes">MES推过来的数据类</param>
        /// <param name="indata">ERP的生产入库单信息</param>
        /// <returns></returns>
        private string PONoPRDINSTOCKQtyCheck(List<R102> mes, List<PRDINSTOCK> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder = new StringBuilder();
            var rs = from a in mes.AsEnumerable()
                     group a by new { a.ERP_MO, a.MO_SEQ } into b
                     select new
                     {
                         ERP_NO = b.Key.ERP_MO,
                         ERP_SEQ = b.Key.MO_SEQ,
                         Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                     };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                            select new { a.ERP_MO, a.MO_SEQ }
                  ).Except(
                from b in indata select new { ERP_MO = b.FBillNo, MO_SEQ = b.FSeq.ToString() }
                );
            if (poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.ERP_MO, p.MO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var rs_mes = from a in rs
                         join b in indata on new { A = a.ERP_NO, B = a.ERP_SEQ } equals new { A = b.FBillNo, B = b.FSeq.ToString() }
                         where a.Qty >b.FNoStockInQty
                         select new
                         {
                             ERP_NO = a.ERP_NO,
                             ERP_SEQ = a.ERP_SEQ,
                             Qty =a.Qty - b.FNoStockInQty
                         };
            if (rs_mes != null)
            {
                foreach (var s in rs_mes)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超了未入库数{2}。", s.ERP_NO, s.ERP_SEQ, s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }
        private string PONoSUBPickMtrltyCheck(List<R014_1> mes, List<SUBPickMtrl> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder = new StringBuilder();
            var rs = from a in mes.AsEnumerable()
                     group a by new { a.ERP_MO, a.MO_SEQ } into b
                     select new
                     {
                         ERP_NO = b.Key.ERP_MO,
                         ERP_SEQ = b.Key.MO_SEQ,
                         Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                     };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                            select new { a.ERP_MO, a.MO_SEQ }
                  ).Except(
                from b in indata select new { ERP_MO = b.FBillNo, MO_SEQ = b.FSeq.ToString() }
                );
            if (poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.ERP_MO, p.MO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var rs_mes = from a in rs
                         join b in indata on new { A = a.ERP_NO, B = a.ERP_SEQ } equals new { A = b.FBillNo, B = b.FSeq.ToString() }
                         where a.Qty > b.FNoPickedQty
                         select new
                         {
                             ERP_NO = a.ERP_NO,
                             ERP_SEQ = a.ERP_SEQ,
                             Qty = a.Qty - b.FNoPickedQty
                         };
            if (rs_mes != null)
            {
                foreach (var s in rs_mes)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超了未入库数{2}。", s.ERP_NO, s.ERP_SEQ, s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }

        private string PONoSUBRETURNMTRLCheck(List<R019_1> mes, List<SUBRETURNMTRL> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder = new StringBuilder();
            var rs = from a in mes.AsEnumerable()
                     group a by new { a.ERP_MO, a.MO_SEQ } into b
                     select new
                     {
                         ERP_NO = b.Key.ERP_MO,
                         ERP_SEQ = b.Key.MO_SEQ,
                         Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                     };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                            select new { a.ERP_MO, a.MO_SEQ }
                  ).Except(
                from b in indata select new { ERP_MO = b.FBillNo, MO_SEQ = b.FSeq.ToString() }
                );
            if (poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.ERP_MO, p.MO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var rs_mes = from a in rs
                         join b in indata on new { A = a.ERP_NO, B = a.ERP_SEQ } equals new { A = b.FBillNo, B = b.FSeq.ToString() }
                         where a.Qty > b.FWipQty
                         select new
                         {
                             ERP_NO = a.ERP_NO,
                             ERP_SEQ = a.ERP_SEQ,
                             Qty = a.Qty - b.FWipQty
                         };
            if (rs_mes != null)
            {
                foreach (var s in rs_mes)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超了未入库数{2}。", s.ERP_NO, s.ERP_SEQ, s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }
        private string PONoPRDReturnMtrlCheck(List<R019> mes, List<PRDReturnMtrl> indata)
        {
            //检测源单是否存在
            if (!indata.Any()) { return "必须有源单..."; }
            StringBuilder stringBuilder = new StringBuilder();
            var rs = from a in mes.AsEnumerable()
                     group a by new { a.ERP_MO, a.MO_SEQ } into b
                     select new
                     {
                         ERP_NO = b.Key.ERP_MO,
                         ERP_SEQ = b.Key.MO_SEQ,
                         Qty = b.Sum(s => decimal.Parse(s.QUANTITY))
                     };
            //检测是否所有源单都存在
            var poExcept = (from a in mes
                            select new { a.ERP_MO, a.MO_SEQ }
                  ).Except(
                from b in indata select new { ERP_MO = b.FBillNo, MO_SEQ = b.FSeq.ToString() }
                );
            if (poExcept.Any())
            {
                foreach (var p in poExcept)
                {
                    string messtr = string.Format("没找到符合条件的订单：{0},行号{1}。", p.ERP_MO, p.MO_SEQ);
                    stringBuilder.Append(messtr);
                }
                return stringBuilder.ToString();
            }
            //与源单剩余入库数量对比
            var rs_mes = from a in rs
                         join b in indata on new { A = a.ERP_NO, B = a.ERP_SEQ } equals new { A = b.FBillNo, B = b.FSeq.ToString() }
                         where a.Qty > b.FWipQty
                         select new
                         {
                             ERP_NO = a.ERP_NO,
                             ERP_SEQ = a.ERP_SEQ,
                             Qty = a.Qty - b.FWipQty
                         };
            if (rs_mes != null)
            {
                foreach (var s in rs_mes)
                {
                    string messtr = string.Format("订单：{0},行号{1}，超了未入库数{2}。", s.ERP_NO, s.ERP_SEQ, s.Qty);
                    stringBuilder.Append(messtr);
                }
            }
            return stringBuilder.ToString();
        }




        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="r170cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<STK_InStock> CreateBatchSTKInStock(List<R170C> r170cs, List<PurchaseOrder> purchaseOrders,string billtype, ref string reason)
        {
            reason = "";
            List<STK_InStock> list = new List<STK_InStock>();
            //源单校验
            string pocheck = PONoInStockQtyCheck(r170cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组
            var headgroup = (from a in r170cs where a != null select new { PO_ID = a.PO_ID, SUP_ID=a.SUP_ID }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.PO_ID)
                    .Select(s => new  
                    {
                        FBillNo=s.FBillNo,
                        FPOOrderEntry_FEntryID=s.FPOOrderEntry_FEntryID,
                        FPOOrderEntry_FSeq=s.FPOOrderEntry_FSeq,
                        FSettleCurrId=s.FSettleCurrId,
                        FSupplierId=s.FSupplierId,
                        FExchangeTypeId=s.FExchangeTypeId,
                        FExchangeRate= _shareController.DecimalPar(s.FExchangeRate),
                        FRemainStockINQty = s.FRemainStockINQty,
                        FPrice=s.FPrice,
                        FPriceTimePoint=s.FPriceTimePoint ,
                        FPayConditionId=s.FPayConditionId,
                        FLocalCurrId=s.FLocalCurrId,
                        FTaxPrice=s.FTaxPrice,
                        FEntryTaxRate=s.FEntryTaxRate,
                        FGiveAway=s.FGiveAway
                    }).Distinct().ToList();
                if(purchase.Count == 0)
                {
                    string mestr = head.PO_ID + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                var order = purchase.FirstOrDefault();
                string supplynumber = order!.FSupplierId;
                string curnumber= order!.FSettleCurrId;
                string ecchangetype= order!.FExchangeTypeId;
                decimal ecchange = order!.FExchangeRate;
                decimal purqty= _shareController.DecimalPar(order!.FRemainStockINQty);
                decimal price = _shareController.DecimalPar(order!.FPrice);
                decimal taxprice = _shareController.DecimalPar(order!.FTaxPrice);
                decimal taxret = int.Parse(order!.FEntryTaxRate) / 100;
                //创建单据头
                STK_InStock inStock = new STK_InStock()
                {
                    FBillTypeID = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = DateTime.Now.ToShortDateString(),
                    FSupplyId = new Dictionary<string, string>() { { "FNUMBER", supplynumber } },
                    FSettleId = new Dictionary<string, string>() { { "FNUMBER", supplynumber } },
                    FSupplierId = new Dictionary<string, string>() { { "FNumber", supplynumber } },
                    FChargeId = new Dictionary<string, string>() { { "FNumber", supplynumber } }
                };
                bool giveaway = order.FGiveAway;
                if (!giveaway)
                {
                     //财务信息
                    STK_InStock.InStockFin stockFin = new STK_InStock.InStockFin()
                    {
                        FSettleOrgId = new Dictionary<string, string>() { { "FNUMBER", "100" } },
                        FSettleCurrId = new Dictionary<string, string>() { { "FNumber", curnumber } },
                        FExchangeTypeId = new Dictionary<string, string>() { { "FNumber", ecchangetype } },
                        FExchangeRate = ecchange,
                        FPriceTimePoint=order.FPriceTimePoint,
                        FPayConditionId = new Dictionary<string, string>() { { "FNumber", order.FPayConditionId } },
                        FLocalCurrId = new Dictionary<string, string>() { { "FNumber", order.FLocalCurrId } },
                        FIsIncludedTax= taxret>0 ? true : false,
                    };
                    inStock.FInStockFin = stockFin;
                }
                
                //添加单据体，按订单号找到它的明细数据                
                List<STK_InStock.InStockEntry> entries = new List<STK_InStock.InStockEntry>();
                var entrygroup= r170cs.Where(s=>s.PO_ID==head.PO_ID).ToList();
                foreach(var entry in entrygroup)
                {
                    //源单内码
                    int sid = 0;
                    //源单行号
                    int sentryid = 0;
                    //剩余未入库数量
                    decimal sqty = 0;
                    //单位编号
                    string unitnumber = string.Empty;
                    var sourceentry = purchaseOrders.Where(s => s.FBillNo == entry.PO_ID && s.FPOOrderEntry_FSeq == entry.PO_SEQ);
                    if (sourceentry != null)
                    {
                        var source = sourceentry.FirstOrDefault();
                        //源单内码
                        sid =int.Parse(source.FID);
                        //源单行号
                        sentryid = int.Parse(source.FPOOrderEntry_FEntryID);
                        //剩余未入库数量
                        sqty = _shareController.DecimalPar(source.FRemainStockINQty);
                        //单位编号
                        unitnumber = source.UnitNumber;
                    }
                    else { unitnumber = entry.UNIT_ID; }
                    string stocknumber = entry.STORE_ID;
                    if(string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr= entry.PO_ID + "第" + entry.PO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.PO_ID + "第" + entry.PO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (string.IsNullOrEmpty(unitnumber))
                    {
                        string mestr = entry.PO_ID + "第" + entry.PO_SEQ + "行【单位编码】不存在";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty= _shareController.DecimalPar(entry.QUANTITY);
                    if(qty <= 0)
                    {
                        string mestr = entry.PO_ID + "第" + entry.PO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if(qty > sqty)
                    {
                        string mestr = entry.PO_ID + "第" + entry.PO_SEQ + "行【数量】不允许大于未入库数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if(reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    STK_InStock.InStockEntry stockEntry = new STK_InStock.InStockEntry()
                    {
                        FPOOrderNo=order!.FBillNo,
                        FSRCBillNo = order!.FBillNo,
                        FPOORDERENTRYID=order!.FPOOrderEntry_FEntryID,
                        FOWNERID = new Dictionary<string, string>() { { "FNUMBER", supplynumber } },
                        FMaterialId = new Dictionary<string, string>() { { "FNumber", martnumber } },
                        FUnitID = new Dictionary<string, string>() { { "FNumber", unitnumber } },
                        FMustQty = sqty,
                        FPURBASENUM = sqty,
                        FStockBaseDen=sqty,
                        FRealQty = qty,
                        FPrice= giveaway ? 0 : price,
                        FTaxPrice= giveaway ? 0 : taxprice,
                        FTaxNetPrice= giveaway ? 0 : price,
                        FEntryTaxRate= giveaway ? 0 : (int)(taxret * 100),
                        FAmount= giveaway ? 0 : Math.Round(price * qty, 2),
                        FAmount_LC = giveaway ? 0 : Math.Round(price * qty* taxret* ecchange, 2), 
                        FAllAmount = giveaway ? 0 : Math.Round(taxprice * qty,2),
                        FAllAmount_LC= giveaway ? 0 : Math.Round(taxprice * qty * taxret* ecchange, 2),
                        FEntryTaxAmount = giveaway ? 0 : Math.Round((taxprice-price) * qty, 2),    //两位小数
                        FTaxAmount_LC = giveaway ? 0 : Math.Round((taxprice - price) * qty * taxret* ecchange, 2),    //价税合计(本位币)-金额，两位小数
                        FAllAmountExceptDisCount = giveaway ? 0 : Math.Round(taxprice * qty, 2),
                        FPriceUnitID = giveaway ? new Dictionary<string, string>() : new Dictionary<string, string>() { { "FNumber", unitnumber } },
                        FRemainInStockUnitId = new Dictionary<string, string>() { { "FNumber", unitnumber } },
                        FRemainInStockQty = qty,
                        //经实测，FRemainInStockQty应当与FRealQty、FPriceUnitQty相等
                        FPriceUnitQty = giveaway ? 0 : qty,
                        FRemainInStockBaseQty = qty,
                        FStockId = new Dictionary<string, string>() { { "FNumber", stocknumber } },
                        FStockLocId = new STK_InStock.InStockEntry.StockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } }
                        },
                        FNote = entry.REMARK,
                        FLot = new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } }, //必须填写编号
                        FPriceBaseQty = qty,
                        FInStockEntry_Link = sid == 0 ? new List<STK_InStock.InStockEntry.InStockEntry_Link>() : new List<STK_InStock.InStockEntry.InStockEntry_Link>()
                            {
                                new STK_InStock.InStockEntry.InStockEntry_Link()
                                {                                    
                                    FInStockEntry_Link_FSBillId =sid.ToString(),
                                    FInStockEntry_Link_FSId = sentryid.ToString(),
                                    FInStockEntry_Link_FRemainInStockBaseQtyOld = purqty,
                                    FInStockEntry_Link_FRemainInStockBaseQty = qty,
                                    FInStockEntry_Link_FBaseUnitQtyOld = purqty,
                                    FInStockEntry_Link_FBaseUnitQty = qty
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }
                if(!giveaway)
                {
                    //再次合计分录
                    var total = from a in entries
                                group a by a.FEntryID into b
                                select new
                                {
                                    FAmount = b.Sum(s => s.FAmount),
                                    FAmount_LC = b.Sum(s => s.FAmount_LC),
                                    FTaxAmount_LC = b.Sum(s => s.FTaxAmount_LC),
                                    FEntryTaxAmount = b.Sum(s => s.FEntryTaxAmount),
                                    FAllAmount = b.Sum(s => s.FAllAmount),
                                    FAllAmount_LC = b.Sum(s => s.FAllAmount_LC)
                                };
                    if (total.Any())
                    {
                        inStock.FInStockFin.FBillTaxAmount = total.FirstOrDefault()!.FEntryTaxAmount;
                        inStock.FInStockFin.FBillAllAmount = total.FirstOrDefault()!.FAllAmount;
                        inStock.FInStockFin.FBillTaxAmount_LC = total.FirstOrDefault()!.FTaxAmount_LC;
                        inStock.FInStockFin.FBillAllAmount_LC = total.FirstOrDefault()!.FAllAmount_LC;
                        inStock.FInStockFin.FBillAmount_LC = total.FirstOrDefault()!.FAmount_LC;
                        inStock.FInStockFin.FBillAmount = total.FirstOrDefault()!.FAmount;
                    }
                }                
                inStock.FInStockEntry = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }


        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="r014cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<PRD_PickMtrl> CreateBatchPRDPickMtrl(List<R014> r014cs, List<PrdPpbomEntry> purchaseOrders, string billtype, ref string reason)
        {
            reason = "";
            List<PRD_PickMtrl> list = new List<PRD_PickMtrl>();
            //源单校验
            string pocheck = PONoPickMtrlQtyCheck(r014cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组:按生产用料清单号分组
            var headgroup = (from a in r014cs where a != null select new { ERP_No = a.ERP_MO, TRX_DATE = a.TRX_DATE }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.ERP_No);
                if (!purchase.Any())
                {
                    string mestr = head.ERP_No + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                var order = purchase.FirstOrDefault();
                string monumber = order!.FMoBillNo1;
                int parseq = int.Parse(order!.FMoEntrySeq1);
                int moid = int.Parse(order!.FMoId1);
                int moentryid = int.Parse(order!.FMoEntryId1);
                string parunit = order!.FUnitID;
                string supplynumber = order!.FWorkshopID;
                string parnumber = order!.FMaterialID;
                string pbomnumber = order!.FBillNo;
                int pid = int.Parse(order!.FID);
                decimal sqty = int.Parse(order!.FNeedQty2) - int.Parse(order!.FPickedQty);
                decimal basesqty = int.Parse(order!.FBaseNeedQty) - int.Parse(order!.FBasePickedQty);

                //基本单位和单位转换率。
                List<BD_UNIT> units = CacheHelper.GetCache<List<BD_UNIT>>("BD_UNIT");
                if (units == null)
                {
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    units = GetUnit();
                }
                //创建单据头
                PRD_PickMtrl inStock = new PRD_PickMtrl()
                {
                    FBillType = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = head.TRX_DATE,
                    FWorkShopId = new Dictionary<string, string>() { { "FNUMBER", supplynumber } }
                };
                //添加单据体，按订单号找到它的明细数据                
                List<PRD_PickMtrl.BillEntry> entries = new List<PRD_PickMtrl.BillEntry>();
                //工单行明细...按生产用料清单号
                List<R014> entrygroup = r014cs.Where(s => s.ERP_MO == head.ERP_No).ToList();
                foreach (var entry in entrygroup)
                {
                    //校验仓库是否正确
                    string stocknumber = entry.STORE_ID;
                    if (string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty = _shareController.DecimalPar(entry.QUANTITY);
                    if (qty <= 0)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if (qty > sqty)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不允许大于未领料数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    //对应这一行属于源单的信息
                    var sourentry = purchase.Where(s => s.FBillNo == entry.ERP_MO && s.FEntity_FSeq == entry.MO_SEQ);
                    int pentryid = int.Parse(sourentry.FirstOrDefault()!.FEntryID);
                    int pseq = int.Parse(entry.MO_SEQ);
                    //当前单位编号
                    string unitnumber = sourentry.FirstOrDefault()!.FUnitID;
                    //当前单位实体
                    var unit = units.Find(s => s.FNumber == unitnumber);
                    //当前单位的换算率
                    decimal unithsl = unit.FConvertNumerator / unit.FConvertDenominator;
                    //当前单位的精度
                    int jd = unit.FPrecision;
                    string baseunitnumber = sourentry.FirstOrDefault()!.FBaseUnitID;
                    PRD_PickMtrl.BillEntry stockEntry = new PRD_PickMtrl.BillEntry()
                    {
                        FParentMaterialId = new Dictionary<string, string> { { "FNumber", parnumber } },
                        FBaseStockActualQty = Math.Round(qty * unithsl, jd),
                        FBaseActualQty = Math.Round(qty * unithsl, jd),       //确定基本单位和常用单位之间的换算关系
                        FMaterialId = new Dictionary<string, string> { { "FNumber", martnumber } },
                        FUnitID = new Dictionary<string, string> { { "FNumber", unitnumber } },
                        FAppQty = sqty,
                        FActualQty = qty,
                        FBaseAppQty = Math.Round(sqty * unithsl, jd),
                        FStockId = new Dictionary<string, string> { { "FNumber", stocknumber } },
                        FStockLocId = new PRD_PickMtrl.BillEntry.StockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>()
                        },
                        FLot = new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } },
                        FEntrtyMemo = entry.REMARK,
                        FMoBillNo = monumber,
                        FMoEntryId = moentryid,
                        FPPBomEntryId = pentryid,
                        FStockAppQty = basesqty,
                        FStockActualQty = qty,
                        FMoId = moid,
                        FMoEntrySeq = parseq,
                        FPPBomBillNo = pbomnumber,
                        FBaseUnitId = new Dictionary<string, string> { { "FNumber", baseunitnumber } },
                        FStockUnitId = new Dictionary<string, string> { { "FNumber", unitnumber } },
                        FEntryWorkShopId = new Dictionary<string, string>() { { "FNumber", supplynumber } },
                        FSrcBillNo = pbomnumber,
                        FEntrySrcInterId = pid,
                        FEntrySrcEnteryId = pentryid,
                        FEntrySrcEntrySeq = pseq,

                        FEntity_Link = pid == 0 ? new List<PRD_PickMtrl.BillEntry.Entity_Link>() : new List<PRD_PickMtrl.BillEntry.Entity_Link>()
                            {
                                new PRD_PickMtrl.BillEntry.Entity_Link()
                                {
                                    FEntity_Link_FSBillId =pid,
                                    FEntity_Link_FSId = pentryid,
                                    FEntity_Link_FBaseActualQtyOld = Math.Round(sqty * unithsl, jd),
                                    FEntity_Link_FBaseActualQty = Math.Round(qty * unithsl, jd)
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }

                inStock.FEntity = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }
        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="r102cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<PRD_INSTOCK> CreateBatchPRDINSTOCK(List<R102> r102cs, List<PRDINSTOCK> purchaseOrders, string billtype, ref string reason)
        {
            reason = "";
            List<PRD_INSTOCK> list = new List<PRD_INSTOCK>();
            //源单校验
            string pocheck = PONoPRDINSTOCKQtyCheck(r102cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组:按生产用料清单号分组
            var headgroup = (from a in r102cs where a != null select new { ERP_No = a.ERP_MO, TRX_DATE = a.TRX_DATE }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.ERP_No);
                if (!purchase.Any())
                {
                    string mestr = head.ERP_No + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                //原单的单据头
                var order = purchase.FirstOrDefault();

                //decimal sqty = int.Parse(order!.FMaterialId) - int.Parse(order!.FPickedQty);
                //decimal basesqty = int.Parse(order!.FBaseNeedQty) - int.Parse(order!.FBasePickedQty);

                //基本单位和单位转换率。
                List<BD_UNIT> units = CacheHelper.GetCache<List<BD_UNIT>>("BD_UNIT");
                if (units == null)
                {
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    units = GetUnit();
                }
                //创建单据头
                PRD_INSTOCK inStock = new()
                {
                    FBillType = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = head.TRX_DATE,
                    FStockOrgId=new Dictionary<string, string>() { { "FNumber",order.FPrdOrgId! } },
                    FPrdOrgId = new Dictionary<string, string>() { { "FNumber", order.FPrdOrgId! } },
                    FWorkShopId = new Dictionary<string, string>() { { "FNUMBER", order.FWorkShopID! } },
                    FOwnerTypeId0=order.FOwnerTypeId,
                    FOwnerId0= !string.IsNullOrEmpty(order.FInStockOwnerId) ? new Dictionary<string, string>() { { "FNumber", order.FInStockOwnerId } } : new Dictionary<string, string>() { { "FNumber", "100" } }
                };
                //添加单据体，按订单号找到它的明细数据                
                List<PRD_INSTOCK.Entity> entries = new List<PRD_INSTOCK.Entity>();
                //工单行明细...按生产用料清单号
                List<R102> entrygroup = r102cs.Where(s => s.ERP_MO == head.ERP_No).ToList();
                foreach (var entry in entrygroup)
                {
                    var sourentry = purchase.Where(s => s.FBillNo == entry.ERP_MO && s.FSeq == entry.MO_SEQ).FirstOrDefault();
                    //应入库数量，来自原单
                    decimal sqty = sourentry.FNoStockInQty;
                    //校验仓库是否正确
                    string stocknumber = entry.STORE_ID;
                    if (string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty = _shareController.DecimalPar(entry.QUANTITY);
                    if (qty <= 0)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if (qty > sqty)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不允许大于未领料数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    //对应这一行属于源单的信息                 
                    int pentryid = int.Parse(sourentry.FEntryId);
                    int pseq = int.Parse(entry.MO_SEQ);
                    //当前单位编号
                    string unitnumber = sourentry.FUnitID;
                    //当前单位实体
                    var unit = units.Find(s => s.FNumber == unitnumber);
                    //当前单位的换算率
                    decimal unithsl = unit.FConvertNumerator / unit.FConvertDenominator;
                    //当前单位的精度
                    int jd = unit.FPrecision;
                    string baseunitnumber = sourentry.FBaseUnitId;
                    PRD_INSTOCK.Entity stockEntry = new PRD_INSTOCK.Entity()
                    {
                        FSrcEntryId = int.Parse(sourentry.FEntryId),
                        FMaterialId = new Dictionary<string, string>() { { "FNumber", sourentry.FMaterialId } },
                        FProductType = sourentry.FProductType,
                        FInStockType = sourentry.FInStockType,
                        FUnitID = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID } },
                        FMustQty = sourentry.FNoStockInQty,
                        FRealQty = decimal.Parse(entry.QUANTITY),                
                        FBaseUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FBaseUnitId } },
                        FBaseMustQty = sourentry.FBaseNoStockInQty,
                        FBaseRealQty = sourentry.FBaseNoStockInQty,
                        FOwnerTypeId0 = sourentry.FInStockOwnerTypeId,
                        FOwnerId = !string.IsNullOrEmpty(sourentry.FInStockOwnerId) ? new Dictionary<string, string>() { { "FNumber",sourentry.FInStockOwnerId } } : new Dictionary<string, string>() { { "FNumber", "100" } },
                        FStockId=new Dictionary<string, string>() { { "FNumber", entry.STORE_ID } },
                        FStockLocId = new PRD_INSTOCK.Entity.StockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } }
                        },
                        FLot=new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } },
                        FWorkShopId1=new Dictionary<string, string>() { { "FNumber", sourentry.FWorkShopID } },
                        FMoBillNo=sourentry.FBillNo,
                        FMoId=int.Parse(sourentry.FID),
                        FMoEntryId=int.Parse(sourentry.FEntryId),
                        FMoEntrySeq=int.Parse(sourentry.FSeq),
                        FMemo= entry.REMARK,
                        FStockUnitId= new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID } },
                        FStockRealQty= qty,
                        FSrcInterId=int.Parse(sourentry.FID),
                        FSrcBillNo=sourentry.FBillNo,
                        FBasePrdRealQty=Math.Round(qty * unithsl, jd),
                        FSrcEntrySeq=int.Parse(sourentry.FSeq),

                        FEntity_Link = int.Parse(sourentry.FID) == 0 ? new List<PRD_INSTOCK.Entity.Entity_Link>() : new List<PRD_INSTOCK.Entity.Entity_Link>()
                            {
                                new PRD_INSTOCK.Entity.Entity_Link()
                                {
                                    FEntity_Link_FSBillId =int.Parse(sourentry.FID),
                                    FEntity_Link_FSId = pentryid,
                                    FEntity_Link_FBaseActualQtyOld = Math.Round(sqty * unithsl, jd),
                                    FEntity_Link_FBaseActualQty = Math.Round(qty * unithsl, jd)
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }

                inStock.FEntity = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }
        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="R014_1cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<SUB_PickMtrl> CreateBatchSUBPickMtrl(List<R014_1> R014_1cs, List<SUBPickMtrl> purchaseOrders, string billtype, ref string reason)
        {
            reason = "";
            List<SUB_PickMtrl> list = new List<SUB_PickMtrl>();
            //源单校验
            string pocheck = PONoSUBPickMtrltyCheck(R014_1cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组:按生产用料清单号分组
            var headgroup = (from a in R014_1cs where a != null select new { ERP_No = a.ERP_MO, TRX_DATE = a.TRX_DATE }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.ERP_No);
                if (!purchase.Any())
                {
                    string mestr = head.ERP_No + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                //原单的单据头
                var order = purchase.FirstOrDefault();

                //decimal sqty = int.Parse(order!.FMaterialId) - int.Parse(order!.FPickedQty);
                //decimal basesqty = int.Parse(order!.FBaseNeedQty) - int.Parse(order!.FBasePickedQty);

                //基本单位和单位转换率。
                List<BD_UNIT> units = CacheHelper.GetCache<List<BD_UNIT>>("BD_UNIT");
                if (units == null)
                {
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    units = GetUnit();
                }
                //创建单据头
                SUB_PickMtrl inStock = new()
                {
                    FBillType = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = head.TRX_DATE,
                    FStockOrgId = new Dictionary<string, string>() { { "FNumber", order.FSupplyOrg! } },
                    FSubOrgId = new Dictionary<string, string>() { { "FNumber", order.FSubOrgId! } },
                    FSupplierId = new Dictionary<string, string>() { { "FNumber", order.FSupplierId! }}
                };
                //添加单据体，按订单号找到它的明细数据                
                List<SUB_PickMtrl.Entity> entries = new List<SUB_PickMtrl.Entity>();
                //工单行明细...按生产用料清单号
                List<R014_1> entrygroup = R014_1cs.Where(s => s.ERP_MO == head.ERP_No).ToList();
                foreach (var entry in entrygroup)
                {
                    var sourentry = purchase.Where(s => s.FBillNo == entry.ERP_MO && s.FSeq == entry.MO_SEQ).FirstOrDefault();
                    //应入库数量，来自原单
                    decimal sqty = sourentry.FNoPickedQty;
                    //校验仓库是否正确
                    string stocknumber = entry.STORE_ID;
                    if (string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty = _shareController.DecimalPar(entry.QUANTITY);
                    if (qty <= 0)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if (qty > sqty)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不允许大于未领料数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    //对应这一行属于源单的信息                 
                    int pentryid = int.Parse(sourentry.FEntryID);
                    int pseq = int.Parse(entry.MO_SEQ);
                    //当前单位编号
                    string unitnumber = sourentry.FUnitID2;
                    //当前单位实体
                    var unit = units.Find(s => s.FNumber == unitnumber);
                    //当前单位的换算率
                    decimal unithsl = unit.FConvertNumerator / unit.FConvertDenominator;
                    //当前单位的精度
                    int jd = unit.FPrecision;
                    string baseunitnumber = sourentry.FBaseUnitID1;
                    SUB_PickMtrl.Entity stockEntry = new SUB_PickMtrl.Entity()
                    {
                        FSrcEntryId = int.Parse(sourentry.FEntryID),
                        FMaterialId = new Dictionary<string, string>() { { "FNumber", entry.MTRL_ID } },
                        FUnitID = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID2 } },                       
                        FActualQty = decimal.Parse(entry.QUANTITY),
                        FStockId = new Dictionary<string, string>() { { "FNumber", entry.STORE_ID } },
                        StockLocId = new SUB_PickMtrl.Entity.FStockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } }
                        },
                        FLOT = new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } },
                        FParentMaterialId = new Dictionary<string, string>() { { "FNumber", sourentry.FMaterialID } },
                        FSrcInterId = int.Parse(sourentry.FID),        
                        FSubReqId = int.Parse(sourentry.FSubReqId),
                        FReserveType = sourentry.FReserveType,
                        FSettleOrgId = new Dictionary<string, string>() { { "FNumber", sourentry.FSettleOrgId } },
                        FPPbomBillNo = sourentry.FBillNo,
                        FSubReqEntryId = int.Parse(sourentry.FSubReqEntryId),
                        FBaseUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FBaseUnitID1 } },              
                        FStockUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID2 } },
                        FSrcPickEntryId = int.Parse(sourentry.FID),
                        FPOOrderSeq = int.Parse(sourentry.FSeq),
                        FKeeperTypeId = sourentry.FOwnerTypeId,
                        FKeeperId = new Dictionary<string, string>() { { "FNumber", sourentry.FOwnerTypeId } },
                        FStockStatusId = new Dictionary<string, string>() { { "FNumber", sourentry.FStockStatusId } },
                        FAllowOverQty = sourentry.FBaseNoPickedQty,
                        FOwnerTypeId = sourentry.FOwnerTypeId,
                        FOwnerId = !string.IsNullOrEmpty(sourentry.FParentOwnerTypeId) ? new Dictionary<string, string>() { { "FNumber", sourentry.FParentOwnerTypeId } } : new Dictionary<string, string>() { { "FNumber", "100" } },
                        FParentOwnerTypeId = sourentry.FParentOwnerTypeId,
                        FParentOwnerId = new Dictionary<string, string>() { { "FNumber", sourentry.FParentOwnerId } },
                        FEntity_Link = int.Parse(sourentry.FID) == 0 ? new List<SUB_PickMtrl.Entity.Entity_Link>() : new List<SUB_PickMtrl.Entity.Entity_Link>()
                            {
                                new SUB_PickMtrl.Entity.Entity_Link()
                                {
                                    FEntity_Link_FSBillId =int.Parse(sourentry.FID),
                                    FEntity_Link_FSId = pentryid,
                                    FEntity_Link_FBaseActualQtyOld = Math.Round(sqty * unithsl, jd),
                                    FEntity_Link_FBaseActualQty = Math.Round(qty * unithsl, jd)
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }

                inStock.FEntity = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }

        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="R019_1cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<SUB_RETURNMTRL> CreateBatchSUBRETURNMTRL(List<R019_1> R019_1cs, List<SUBRETURNMTRL> purchaseOrders, string billtype, ref string reason)
        {
            reason = "";
            List<SUB_RETURNMTRL> list = new List<SUB_RETURNMTRL>();
            //源单校验
            string pocheck = PONoSUBRETURNMTRLCheck(R019_1cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组:按生产用料清单号分组
            var headgroup = (from a in R019_1cs where a != null select new { ERP_No = a.ERP_MO, TRX_DATE = a.TRX_DATE }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.ERP_No);
                if (!purchase.Any())
                {
                    string mestr = head.ERP_No + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                //原单的单据头
                var order = purchase.FirstOrDefault();

                //decimal sqty = int.Parse(order!.FMaterialId) - int.Parse(order!.FPickedQty);
                //decimal basesqty = int.Parse(order!.FBaseNeedQty) - int.Parse(order!.FBasePickedQty);

                //基本单位和单位转换率。
                List<BD_UNIT> units = CacheHelper.GetCache<List<BD_UNIT>>("BD_UNIT");
                if (units == null)
                {
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    units = GetUnit();
                }
                //创建单据头
                SUB_RETURNMTRL inStock = new()
                {
                    FBillType = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = head.TRX_DATE,
                    FStockOrgId = new Dictionary<string, string>() { { "FNumber", order.FSupplyOrg! } },
                    FStockId0 = new Dictionary<string, string>() { { "FNumber", order.FStockID! } },
                    FSubOrgId = new Dictionary<string, string>() { { "FNumber", order.FSubOrgId! } },
                    FSubSupplierId = new Dictionary<string, string>() { { "FNumber", order.FSupplierId! } },
                    FOwnerTypeId0 = order.FOwnerTypeId,
                    FOwnerId0 = new Dictionary<string, string>() { { "FNumber", order.FOwnerID! } },
                };
                //添加单据体，按订单号找到它的明细数据                
                List<SUB_RETURNMTRL.Entity> entries = new List<SUB_RETURNMTRL.Entity>();
                //工单行明细...按生产用料清单号
                List<R019_1> entrygroup = R019_1cs.Where(s => s.ERP_MO == head.ERP_No).ToList();
                foreach (var entry in entrygroup)
                {
                    var sourentry = purchase.Where(s => s.FBillNo == entry.ERP_MO && s.FSeq == entry.MO_SEQ).FirstOrDefault();
                    //应入库数量，来自原单
                    decimal sqty = sourentry.FWipQty;
                    //校验仓库是否正确
                    string stocknumber = entry.STORE_ID;
                    if (string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty = _shareController.DecimalPar(entry.QUANTITY);
                    if (qty <= 0)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if (qty > sqty)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不允许大于未领料数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    //对应这一行属于源单的信息                 
                    int pentryid = int.Parse(sourentry.FEntryID);
                    int pseq = int.Parse(entry.MO_SEQ);
                    //当前单位编号
                    string unitnumber = sourentry.FUnitID;
                    //当前单位实体
                    var unit = units.Find(s => s.FNumber == unitnumber);
                    //当前单位的换算率
                    decimal unithsl = unit.FConvertNumerator / unit.FConvertDenominator;
                    //当前单位的精度
                    int jd = unit.FPrecision;
                    string baseunitnumber = sourentry.FUnitID;
                    SUB_RETURNMTRL.Entity stockEntry = new SUB_RETURNMTRL.Entity()
                    {
                        FSrcEntryId = int.Parse(sourentry.FEntryID),
                        FMaterialId = new Dictionary<string, string>() { { "FNumber", entry.MTRL_ID } },
                        FUnitID = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID } },
                        FAPPQty = decimal.Parse(entry.QUANTITY),
                        FQty = decimal.Parse(entry.QUANTITY),   
                        FStockId = new Dictionary<string, string>() { { "FNumber", entry.STORE_ID } },
                        FStockLocId = new SUB_RETURNMTRL.Entity.StockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } }
                        },
                        FLot = new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } },
                        FSUBReqBillNo = sourentry.FBillNo,
                        FSrcEntrySeq = int.Parse(sourentry.FSeq),
                        FParentMaterialId = new Dictionary<string, string>() { { "FNumber", sourentry.FMaterialID } },
                        FSUBReqId = int.Parse(sourentry.FSubReqId),
                        FSUBReqEntrySeq = int.Parse(sourentry.FSubReqEntrySeq),
                        FPPBOMEntryId = int.Parse(sourentry.FSubReqEntryId),
                        FSubReqEntryId = int.Parse(sourentry.FSubReqEntryId),
                        FOwnerTypeId0 = sourentry.FOwnerTypeId,
                        FOwnerId = new Dictionary<string, string>() { { "FNumber", sourentry.FOwnerID } },
                        FBaseUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FBaseUnitId } },
                        FReserveType = sourentry.FReserveType,
                        FSettleOrgId = new Dictionary<string, string>() { { "FNumber", sourentry.FSettleOrgId } },
                        FStockUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID } },
                        FSecUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID } },
                        FMtoNo = sourentry.FMtoNo,
                        FProjectNo = sourentry.FProjectNo,
                        FStockStatusId = new Dictionary<string, string>() { { "FNumber", sourentry.FStockStatusId } },
                        FKeeperId = new Dictionary<string, string>() { { "FNumber", sourentry.FSupplyOrg } },
                        FProcessId = new Dictionary<string, string>() { { "FNumber", sourentry.FProcessID } },
                        FOperId = int.Parse(sourentry.FOperID),
                        FBomId = new Dictionary<string, string>() { { "FNumber", sourentry.FBomId } },
                        FParentOwnerTypeId = sourentry.FParentOwnerTypeId,
                        FParentOwnerId = new Dictionary<string, string>() { { "FNumber", sourentry.FParentOwnerId } },
                        FPPBomBillNo = sourentry.FBillNo,
                        FEntity_Link = int.Parse(sourentry.FID) == 0 ? new List<SUB_RETURNMTRL.Entity.Entity_Link>() : new List<SUB_RETURNMTRL.Entity.Entity_Link>()
                            {
                                new SUB_RETURNMTRL.Entity.Entity_Link()
                                {
                                    FEntity_Link_FSBillId =int.Parse(sourentry.FID),
                                    FEntity_Link_FSId = pentryid,
                                    FEntity_Link_FBaseActualQtyOld = Math.Round(sqty * unithsl, jd),
                                    FEntity_Link_FBaseActualQty = Math.Round(qty * unithsl, jd)
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }

                inStock.FEntity = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }
       
        /// <summary>
        /// 在RB系统校验源单信息，并转换成Cloud的实体类
        /// </summary>
        /// <param name="R019cs">接收到的数据</param>
        /// <param name="purchaseOrders">源单信息</param>
        /// <param name="billtype">FBillTypeID的FNumber属性</param>
        /// <param name="reason">如果错误，则返回消息</param>
        /// <returns></returns>
        private List<PRD_ReturnMtrl> CreateBatchPRDReturnMtrl(List<R019> R019cs, List<PRDReturnMtrl> purchaseOrders, string billtype, ref string reason)
        {
            reason = "";
            List<PRD_ReturnMtrl> list = new List<PRD_ReturnMtrl>();
            //源单校验
            string pocheck = PONoPRDReturnMtrlCheck(R019cs, purchaseOrders);
            if (!string.IsNullOrEmpty(pocheck))
            {
                reason += reason == "" ? pocheck : "；" + pocheck;
                return list;
            }
            //将inStocks按源单分组，形成单据头组:按生产用料清单号分组
            var headgroup = (from a in R019cs where a != null select new { ERP_No = a.ERP_MO, TRX_DATE = a.TRX_DATE }).Distinct().ToList();
            foreach (var head in headgroup)
            {
                //源单信息
                var purchase = purchaseOrders.Where(s => s.FBillNo == head.ERP_No);
                if (!purchase.Any())
                {
                    string mestr = head.ERP_No + "不存在";
                    reason += reason == "" ? mestr : "；" + mestr;
                    break;
                }
                //原单的单据头
                var order = purchase.FirstOrDefault();

                //decimal sqty = int.Parse(order!.FMaterialId) - int.Parse(order!.FPickedQty);
                //decimal basesqty = int.Parse(order!.FBaseNeedQty) - int.Parse(order!.FBasePickedQty);

                //基本单位和单位转换率。
                List<BD_UNIT> units = CacheHelper.GetCache<List<BD_UNIT>>("BD_UNIT");
                if (units == null)
                {
                    //重新加入缓存
                    Thread uthread = new Thread(AddUnitCache);
                    uthread.IsBackground = true;
                    uthread.Start();
                    units = GetUnit();
                }
                //创建单据头
                PRD_ReturnMtrl inStock = new()
                {
                    FBillType = new Dictionary<string, string>() { { "FNUMBER", billtype } },
                    FDate = head.TRX_DATE,
                    FPrdOrgId = new Dictionary<string, string>() { { "FNumber", order.FPrdOrgId! } },
                    FOwnerTypeId0 = order.FOwnerTypeId,           
                    FOwnerId0 = new Dictionary<string, string>() { { "FNumber", order.FOwnerID! } },
                };
                //添加单据体，按订单号找到它的明细数据                
                List<PRD_ReturnMtrl.Entity> entries = new List<PRD_ReturnMtrl.Entity>();
                //工单行明细...按生产用料清单号
                List<R019> entrygroup = R019cs.Where(s => s.ERP_MO == head.ERP_No).ToList();
                foreach (var entry in entrygroup)
                {
                    var sourentry = purchase.Where(s => s.FBillNo == entry.ERP_MO && s.FSeq == entry.MO_SEQ).FirstOrDefault();
                    //应入库数量，来自原单
                    decimal sqty = sourentry.FWipQty;
                    //校验仓库是否正确
                    string stocknumber = entry.STORE_ID;
                    if (string.IsNullOrEmpty(stocknumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【仓库】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    string martnumber = entry.MTRL_ID;
                    if (string.IsNullOrEmpty(martnumber))
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【物料编码】不能为空";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    decimal qty = _shareController.DecimalPar(entry.QUANTITY);
                    if (qty <= 0)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不正确";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    else if (qty > sqty)
                    {
                        string mestr = entry.ERP_MO + "第" + entry.MO_SEQ + "行【数量】不允许大于未领料数";
                        reason += reason == "" ? mestr : "；" + mestr;
                    }
                    if (reason.Length > 0) { break; }    //遇到错误直接退出，不用浪费时间了...
                    //对应这一行属于源单的信息                 
                    int pentryid = int.Parse(sourentry.FEntryID);
                    int pseq = int.Parse(entry.MO_SEQ);
                    //当前单位编号
                    string unitnumber = sourentry.FUnitID2;
                    //当前单位实体
                    var unit = units.Find(s => s.FNumber == unitnumber);
                    //当前单位的换算率
                    decimal unithsl = unit.FConvertNumerator / unit.FConvertDenominator;
                    //当前单位的精度
                    int jd = unit.FPrecision;
                    string baseunitnumber = sourentry.FUnitID2;
                    PRD_ReturnMtrl.Entity stockEntry = new PRD_ReturnMtrl.Entity()
                    {
                        FEntryID = int.Parse(sourentry.FEntryID),
                        FMaterialId = new Dictionary<string, string>() { { "FNumber", entry.MTRL_ID } },
                        FUnitID = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID2 } },
                        FAPPQty = decimal.Parse(entry.QUANTITY),
                        FQty = decimal.Parse(entry.QUANTITY),
                        FStockId = new Dictionary<string, string>() { { "FNumber", entry.STORE_ID } },
                        StockLocId = new PRD_ReturnMtrl.Entity.FStockLocId()
                        {
                            FSTOCKLOCID__FF100001 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } },
                            FSTOCKLOCID__FF100002 = new Dictionary<string, string>() { { "FNumber", entry.STORELOC_ID } }
                        },
                        FLot = new Dictionary<string, string>() { { "FNumber", entry.ERP_LOTNO } },
                        FEntrySrcEntrySeq = int.Parse(sourentry.FSeq),                
                        FPPBomBillNo = sourentry.FBillNo,
                        FProcessId = new Dictionary<string, string>() { { "FNumber", sourentry.FProcessID } },
                        FParentMaterialId = new Dictionary<string, string>() { { "FNumber", sourentry.FMaterialID } },
                        FPPBOMEntryId = int.Parse(sourentry.FEntryID),
                        FMoId = int.Parse(sourentry.FMoId1),
                        FReserveType = sourentry.FReserveType,
                        FMoBillNo = sourentry.FMoBillNo1,
                        FMoEntryId = int.Parse(sourentry.FMoEntryId1),
                        FMoEntrySeq = int.Parse(sourentry.FMoEntrySeq1),
                        FStockUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID2 } },
                        FSecUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FUnitID2 } },
                        FMtoNo = sourentry.FMTONO,
                        FProjectNo = sourentry.FProjectNO,
                        FStockStatusId = new Dictionary<string, string>() { { "FNumber", sourentry.FStockStatusId } },
                        FKeeperId = sourentry.FPrdOrgId,
                        FOperId = int.Parse(sourentry.FOperID),
                        FBomId = new Dictionary<string, string>() { { "FNumber", sourentry.FBomId2 } },
                        FBaseUnitId = new Dictionary<string, string>() { { "FNumber", sourentry.FBaseUnitID1 } },
                        FBaseAppQty = sourentry.FBaseWipQty,
                        FBaseQty = sourentry.FBaseWipQty,
                        FOwnerTypeId = sourentry.FOwnerTypeId,
                        FOwnerId = new Dictionary<string, string>() { { "FNumber", sourentry.FOwnerID } },
                        FEntrySrcEnteryId = int.Parse(sourentry.FEntryID),
                        FEntrySrcInterId = int.Parse(sourentry.FID),
                        FWorkShopId1 = new Dictionary<string, string>() { { "FNumber", sourentry.FWorkshopID } },
                        FParentOwnerId = new Dictionary<string, string>() { { "FNumber", sourentry.FEntrustPickOrgId } },
                        FEntity_Link = int.Parse(sourentry.FID) == 0 ? new List<PRD_ReturnMtrl.Entity.Entity_Link>() : new List<PRD_ReturnMtrl.Entity.Entity_Link>()
                            {
                                new PRD_ReturnMtrl.Entity.Entity_Link()
                                {
                                    FEntity_Link_FSBillId =int.Parse(sourentry.FID),
                                    FEntity_Link_FSId = pentryid,
                                    FEntity_Link_FBaseActualQtyOld = Math.Round(sqty * unithsl, jd),
                                    FEntity_Link_FBaseActualQty = Math.Round(qty * unithsl, jd)
                                }
                            }
                    };
                    entries.Add(stockEntry);
                }

                inStock.FEntity = entries;
                //财务费用，隶属于单据体
                list.Add(inStock);
            }
            return list;
        }
        
        private BreakData ExistsDoubleQueid<T>(List<T> inputdata,string DocType) where T : class
        {
            BreakData breakData=new BreakData() { Status=false};
            Type type = typeof(T);
            PropertyInfo[] propertyInfos = type.GetProperties();
            var propertyInfo = propertyInfos.Where(s => s.Name == "QUEUE_ID");
            if (propertyInfo.Any())
            {
                try
                {
                    List<string> strings = new List<string>();
                    PropertyInfo infos = propertyInfos.Where(s => s.Name == "QUEUE_ID").FirstOrDefault()!;
                    foreach (var obj in inputdata)
                    {
                        object v= infos.GetValue(obj)!;
                        strings.Add(v.ToString());
                    }
                    string sql = string.Format("select * from r_ReciveDataBack where FDocType='{0}' and QUEUE_ID in ({1})", DocType,string.Join(',', strings.ToArray()));
                    //直接SQL查询更快！！！
                    string messstr = string.Empty;
                    DataSet? dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, null, ref messstr!, false);
                    if(dataSet != null)
                    {
                        DataTable dataTable = dataSet.Tables[0];
                        var dt = (from a in dataTable.AsEnumerable()
                                 select new
                                 {
                                     QUEUE_ID=a.Field<int>("QUEUE_ID").ToString(),
                                     FDocType = a.Field<string>("FDocType")!,
                                     FBillNo = a.Field<string>("FBillNo")!,
                                     FErpID = a.Field<int>("FErpID"),
                                     FSeq = a.Field<int>("FSeq")
                                 }).ToList();
                        if(dt.Any())
                        {
                            breakData.Message = dt;
                        }
                        else { breakData.Status = true; }
                    }
                    else { breakData.Message = messstr; }
                }
                catch (Exception ex)
                {
                    breakData.Message = ex.Message;
                    //throw;
                }
            }
            else
            {
                breakData.Message = "传入的数据中必须有字段【QUEUE_ID】";
            }            
            return breakData;
        }
        /// <summary>
        /// 提供批量保存、提交并审核普通采购入库单、VMI入库单方法
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchInStockAsync(DataTable dataTable,int fid,int postmid,int fchildmid,string data)
        {
            BreakData breakData = new BreakData() { Status=false , DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就采购订单号，查询源单并校验 
            List<PurchaseOrder> purchaseOrders = _chiledselect.GetSourceBillEntry<PurchaseOrder>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R170C>? mes_POInStocks = _shareController.DataConvertClass<R170C>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();
                    //为采购入库类赋值
                    List<STK_InStock> inStocks = CreateBatchSTKInStock(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);
                    if (inStocks.Count()>0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);
                            
                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                 SaveReciveDataBackAsync(breakData,dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";                                
                            }                            
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message =string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }
        /// <summary>
        /// 根据金蝶系统返回字段，整理成list并返回给推送方
        /// </summary>
        /// <param name="doctype">接口类型</param>
        /// <param name="mesobj">推送的数据</param>
        /// <param name="billlist">ERP返回的集合</param>
        /// <param name="dataBacks">返回给推送方的今本</param>
        /// <returns></returns>
        private List<string> GetNewBillNoList<T>(string doctype, List<T>? mesobj, 
            List<Dictionary<string, string>> billlist,ref List<ReciveDataBack> dataBacks) where T : class
        {
            List<string> billnolist = new List<string>();
            Type type = typeof(T);
            PropertyInfo[] propertyInfos = type.GetProperties();
            var Q = propertyInfos.Where(s => s.Name == "QUEUE_ID");
            if (!Q.Any())
            {
                return billnolist;
            }
            PropertyInfo propertyInfo = Q.FirstOrDefault()!;
            dataBacks = new List<ReciveDataBack>();
            if (billlist != null)
            {
                if (billlist.FirstOrDefault()!.ContainsKey("FBillNo"))
                {
                    int i = 0;
                    foreach (Dictionary<string, string> bill in billlist)
                    {
                        billnolist.Add(bill["FBillNo"]);    //注意？后台配置r_DataSaveBatch时，FID,FBillNo,FSeq是必须的...
                        dataBacks.Add(
                            new ReciveDataBack()
                        {
                            FBillNo = bill["FBillNo"],
                            FDocType = doctype,
                            FErpID = int.Parse(bill["FID"]),
                            FSeq = int.Parse(bill["FSeq"]),
                            QUEUE_ID = (string)propertyInfo.GetValue(mesobj[i])
                            }
                        );
                        i++;
                    }
                }
            }
            return billnolist;
        }
        /// <summary>
        /// 成功保存到ERP之后备份主键信息到沃比数据库
        /// </summary>
        /// <param name="breakData">需要返回给推送方的类</param>
        /// <param name="dataBacks">需要保存的数据集</param>
        private async void SaveReciveDataBackAsync(BreakData breakData, List<ReciveDataBack> dataBacks)
        {
            try
            {
                _context.r_ReciveDataBack!.AddRange(dataBacks);
                await _context.SaveChangesAsync();
                breakData.Status = true;
            }
            catch (Exception ex)
            {
                breakData.Message="数据已成功保存到ERP，但" + ex.Message;
                breakData.Status = false;
                //throw;
            }
        }

        /// <summary>
        /// 提供批量保存、提交并审核普通生产领料单
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchPickMtrlAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        {
            BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就ERP生产用料清单号、行号，查询源单，并校验
            List<PrdPpbomEntry> purchaseOrders = _chiledselect.GetSourceBillEntry<PrdPpbomEntry>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R014>? mes_POInStocks = _shareController.DataConvertClass<R014>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();

                    List<PRD_PickMtrl> inStocks = CreateBatchPRDPickMtrl(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);
                    if (inStocks.Count() > 0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                SaveReciveDataBackAsync(breakData, dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
                            }
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }

        /// <summary>
        /// 提供批量保存、提交并审核普通生产入库单
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchINSTOCKAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        {
            BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就ERP生产用料清单号、行号，查询源单，并校验
            List<PRDINSTOCK> purchaseOrders = _chiledselect.GetSourceBillEntry<PRDINSTOCK>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R102>? mes_POInStocks = _shareController.DataConvertClass<R102>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();

                    List<PRD_INSTOCK> inStocks = CreateBatchPRDINSTOCK(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);
                    if (inStocks.Count() > 0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                SaveReciveDataBackAsync(breakData, dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
                            }
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }
        /// <summary>
        /// 提供批量保存、提交并审核普通委外领料单
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchSUBPickMtrlAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        {
            BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就ERP生产用料清单号、行号，查询源单，并校验
            List<SUBPickMtrl> purchaseOrders = _chiledselect.GetSourceBillEntry<SUBPickMtrl>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R014_1>? mes_POInStocks = _shareController.DataConvertClass<R014_1>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();

                    List<SUB_PickMtrl> inStocks = CreateBatchSUBPickMtrl(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);
                    if (inStocks.Count() > 0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                SaveReciveDataBackAsync(breakData, dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
                            }
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }


        //private async Task<BreakData> SaveBatchINSTOCKAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        //{
        //    BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
        //    string reason = string.Empty;
        //    //应当就ERP生产用料清单号、行号，查询源单，并校验
        //    List<PrdPpbomEntry> purchaseOrders = _chiledselect.GetSourceBillEntry<PrdPpbomEntry>(dataTable, fchildmid, ref reason);
        //    if (!string.IsNullOrEmpty(reason))
        //    {
        //        breakData.Message = reason;
        //    }
        //    else
        //    {
        //        List<R014>? mes_POInStocks = _shareController.DataConvertClass<R014>(data, ref reason);
        //        if (mes_POInStocks != null)
        //        {
        //            //推送数据
        //            DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
        //                .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
        //                .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
        //                .AsNoTracking()
        //                .FirstOrDefaultAsync();
        //            List<PRD_PickMtrl> inStocks = CreateBatchPRDPickMtrl(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);
        //            if (inStocks.Count() > 0 && reason == "")
        //            {
        //                //校验是否有重复推单
        //                breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
        //                if (!breakData.Status)
        //                {
        //                    breakData.DataSet = mes_POInStocks;     //将源数据返回去...
        //                    return breakData;
        //                }
        //                breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
        //                if (breakData.Status)
        //                {
        //                    List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
        //                    //提取出创建好的单据编号
        //                    List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
        //                    List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

        //                    if (billnolist.Count > 0)
        //                    {
        //                        //写入沃比数据库，避免重复推送
        //                        SaveReciveDataBackAsync(breakData, dataBacks);
        //                        if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
        //                        {
        //                            //提交单据
        //                            breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
        //                            if (breakData.Status)
        //                            {
        //                                //继续审核单据
        //                                breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
        //                                //if (breakData.Status)
        //                                //{
        //                                //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
        //                                //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
        //                                //}
        //                            }
        //                        }
        //                    }
        //                    else
        //                    {
        //                        breakData.Status = false;
        //                        breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
        //                    }
        //                    breakData.DataSet = billlist;
        //                }
        //            }
        //            else
        //            {
        //                breakData.Message = reason;
        //            }
        //        }
        //        else
        //        {
        //            breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
        //        }
        //    }
        //    return breakData;
        //}

        /// <summary>
        /// 提供批量保存、提交并审核普通生产退料单
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchPRDReturnMtrlAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        {
            BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就ERP生产用料清单号、行号，查询源单，并校验
            List<PRDReturnMtrl> purchaseOrders = _chiledselect.GetSourceBillEntry<PRDReturnMtrl>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R019>? mes_POInStocks = _shareController.DataConvertClass<R019>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();
                    List<PRD_ReturnMtrl> inStocks = CreateBatchPRDReturnMtrl(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);

                    if (inStocks.Count() > 0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                SaveReciveDataBackAsync(breakData, dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
                            }
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }

        /// <summary>
        /// 提供批量保存、提交并审核普通委外退料单
        /// </summary>
        /// <param name="dataTable">接收到的数据，已转换为table</param>
        /// <param name="fid">FFunctionID</param>
        /// <param name="postmid">主查询doctypeid</param>
        /// <param name="fchildmid">子查询doctypeid</param>
        /// <param name="data">接收到的直接数据</param>
        /// <returns></returns>
        private async Task<BreakData> SaveBatchSUBRETURNMTRLAsync(DataTable dataTable, int fid, int postmid, int fchildmid, string data)
        {
            BreakData breakData = new BreakData() { Status = false, DataSet = JsonConvert.DeserializeObject(data) };
            string reason = string.Empty;
            //应当就ERP生产用料清单号、行号，查询源单，并校验
            List<SUBRETURNMTRL> purchaseOrders = _chiledselect.GetSourceBillEntry<SUBRETURNMTRL>(dataTable, fchildmid, ref reason);
            if (!string.IsNullOrEmpty(reason))
            {
                breakData.Message = reason;
            }
            else
            {
                List<R019_1>? mes_POInStocks = _shareController.DataConvertClass<R019_1>(data, ref reason);
                if (mes_POInStocks != null)
                {
                    //推送数据
                    DataSaveBatch? dataSave = await _context.r_DataSaveBatch!
                        .Include(s => s.GetForm).ThenInclude(s => s.functions)    //必须提供外键表数据
                        .Where(s => s.GetForm.FFunctionID == fid && s.FDocTypeID == postmid)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();
                    List<SUB_RETURNMTRL> inStocks = CreateBatchSUBRETURNMTRL(mes_POInStocks, purchaseOrders, dataSave.FErpBillType, ref reason);

                    if (inStocks.Count() > 0 && reason == "")
                    {
                        //校验是否有重复推单
                        breakData = ExistsDoubleQueid(mes_POInStocks, dataSave.GetForm.FDocType);
                        if (!breakData.Status)
                        {
                            breakData.DataSet = mes_POInStocks;     //将源数据返回去...
                            return breakData;
                        }
                        breakData = await SaveBatchAsync(dataSave, dataSave.GetForm.functions.FUrl, dataSave.GetForm.FDBName, inStocks);
                        if (breakData.Status)
                        {
                            List<ReciveDataBack> dataBacks = new List<ReciveDataBack>();
                            //提取出创建好的单据编号
                            List<Dictionary<string, string>> billlist = (List<Dictionary<string, string>>)breakData.DataSet!;
                            List<string> billnolist = GetNewBillNoList(dataSave.GetForm.FDocType, mes_POInStocks, billlist, ref dataBacks);

                            if (billnolist.Count > 0)
                            {
                                //写入沃比数据库，避免重复推送
                                SaveReciveDataBackAsync(breakData, dataBacks);
                                if (dataSave.FIsAutoSubmitAndAudit && breakData.Status) //自动提交、审核
                                {
                                    //提交单据
                                    breakData = await SubmitCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FSubmitUrl);
                                    if (breakData.Status)
                                    {
                                        //继续审核单据
                                        breakData = await AuditCloudAsync(billnolist!, dataSave!.GetForm.FDBName, dataSave.FAuditUrl);
                                        //if (breakData.Status)
                                        //{
                                        //    //反写订单，除非特殊，否则使用Cloud标准的反写规则，系统自动反写
                                        //    breakData = await UpdateCGDD01_SYSAsync(inStocks, dataSave.GetForm.functions.FUrl);
                                        //}
                                    }
                                }
                            }
                            else
                            {
                                breakData.Status = false;
                                breakData.Message = "单据已保存成功，但返回参数中不包含单据编号，无法提交审核！";
                            }
                            breakData.DataSet = billlist;
                        }
                    }
                    else
                    {
                        breakData.Message = reason;
                    }
                }
                else
                {
                    breakData.Message = string.IsNullOrEmpty(reason) ? "输入数据转换出错" : reason;
                }
            }
            return breakData;
        }
    
    }
}

