using DirectService.Tools;
using JLHHJSvr.BLL;
using JLHHJSvr.Com.Model;
using JLHHJSvr.Excutor;
using JLHHJSvr.LJException;
using JLHHJSvr.Tools;
using LJLib.DAL.SQL;
using NPOI.HSSF.Record;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Configuration;
using static JLHHJSvr.Helper.CacheHelper;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Tab;

namespace JLHHJSvr.Helper
{
    internal class SoftBedHelper : HelperBase
    {
		/// <summary>
		/// 获取软床报价单据
		/// </summary>
		/// <param name="billid"></param>
		/// <param name="fields"></param>
		/// <param name="bill"></param>
        public u_softbed GetSoftBed(int billid,string fields = null)
        {
            fields = fields ?? @"softbed_id,softbed_code,softbed_relcode,softbed_name,deptid,create_date,create_emp,mtrlmode,mtrltype,has_headboard,has_nightstand,has_bedframe,is_template,
                                template_id,template_code,template_name,commission,taxes,taxrate,other_rate,extras_cost,money_type,moneyrate,dscrp,costamt,nottax_factory_cost,nottax_dept_cost,
                                dept_cost,foreign_cost,total_mtrl_cost,total_hr_cost,total_cost,version,flag,audit_date,audit_emp,update_date,update_emp";
            var bill = new u_softbed() { softbed_id = billid };
			if (DbSqlHelper.SelectOne(cmd, bill, fields) == 0) return null;
			return bill;
        }

		/// <summary>
		/// 获取软床报价单据明细
		/// </summary>
		/// <param name="billid"></param>
		/// <param name="fields"></param>
		/// <param name="mxlist"></param>
        public List<u_softbed_mx> GetSoftBedMxList(int billid,string fields = null)
        {
            fields = fields ?? @"softbed_id,printid,formulaid,pzid,mtrlid,mtrlname,mtrlcode,mtrlmode,unit,has_type,allow_edit,cutting_length,cutting_width,cutting_qty,
                                useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt,pzname,formulaname,parts_type";
            var mxlist = new List<u_softbed_mx>();

            var selectStr = @"SELECT u_softbed_mx.softbed_id
									,u_softbed_mx.printid
									,u_softbed_mx.formulaid
									,u_softbed_mx.pzid
									,u_softbed_mx.mtrlid
									,u_softbed_mx.mtrlname
									,u_softbed_mx.mtrlcode
									,u_softbed_mx.mtrlmode
									,u_softbed_mx.unit
									,u_softbed_mx.has_type
									,u_softbed_mx.allow_edit
									,u_softbed_mx.cutting_length
									,u_softbed_mx.cutting_width
									,u_softbed_mx.cutting_qty
									,u_softbed_mx.useqty
									,u_softbed_mx.use_formula
									,u_softbed_mx.use_formula_str
									,u_softbed_mx.actual_useqty
									,u_softbed_mx.loss_rate
									,u_softbed_mx.price
									,u_softbed_mx.price_formula
									,u_softbed_mx.price_formula_str
									,u_softbed_mx.cost_price
									,u_softbed_mx.cost_amt
									,ISNULL(u_configure_code.name,u_softbed_mx.pzname) AS pzname
									,u_softbed_mx.parts_type
									,ISNULL(u_softbed_formula.formulaname,'') AS formulaname
								FROM u_softbed_mx
								LEFT JOIN u_configure_code ON u_softbed_mx.pzid = u_configure_code.pzid
								LEFT JOIN u_softbed_formula ON u_softbed_mx.formulaid = u_softbed_formula.formulaid
								";

            DbSqlHelper.SelectJoin(cmd, selectStr, "softbed_id = @billid", new Dictionary<string, object>() { { "@billid", billid } }, "has_type,printid", fields, 0, 0, mxlist);

			return mxlist;
        }
		public List<u_softbed_mx> GetChangeSoftBedMxList(int billid,List<u_softbed_mx> mxList,List<u_configure_codemx> codeMxList)
		{
			var newList = new List<u_softbed_mx>();
			var pzid0List = new List<u_softbed_mx>();
			var softbed = GetSoftBed(billid, "billid,softbed_code,has_headboard,has_nightstand,has_bedframe,is_template,template_id");
			if (softbed == null) return newList;
            // 换料清单
            var bomList = GetSoftBedMxBomList(codeMxList);
            //         var typeDict = new Dictionary<string, List<u_softbed_mx>>();
            //foreach(var mx in mxList)
            //{
            //	var key = $"{mx.has_type}|{mx.pzid}";
            //	if(!typeDict.ContainsKey(key))
            //	{
            //		typeDict.Add(key, new List<u_softbed_mx>());
            //	}

            //	typeDict[key].Add(mx);

            //	if (mx.pzid == 0) pzid0List.Add(mx);
            //         }

            // 原Dictionary替换为List<KeyValuePair>，维护键值对的插入顺序
            var typeList = new List<KeyValuePair<string, List<u_softbed_mx>>>();
            foreach (var mx in mxList)
            {
                var key = $"{mx.has_type}|{mx.pzid}";
                var existingItem = typeList.FirstOrDefault(kvp => kvp.Key == key);

                if (existingItem.Equals(default(KeyValuePair<string, List<u_softbed_mx>>)))
                {
                    var newMxList = new List<u_softbed_mx> { mx };
                    typeList.Add(new KeyValuePair<string, List<u_softbed_mx>>(key, newMxList));
                }
                else
                {
                    existingItem.Value.Add(mx);
                }

                if (mx.pzid == 0)
                {
                    pzid0List.Add(mx);
                }
            }
            var bomDict = new Dictionary<string, List<u_softbed_mx>>();
            foreach (var bom in bomList)
            {
                var key = $"{bom.has_type}|{bom.pzid}";
                if (!bomDict.ContainsKey(key))
                {
                    bomDict.Add(key, new List<u_softbed_mx>());
                }
                bomDict[key].Add(bom);
            }
            /**
			 * 1、模板报价
			 * 2、非模板报价
			 * 仅替换配置，保留其他明细信息
			 * 1、如果明细存在bomList中，证明没有替换，直接添加到newList
			 * 2、如果明细不存在bomList中，证明可能是给替换的(2.1)或者是非部件(即手动添加2.2)
			 */
            foreach (var kvp in typeList)
            {
                if (bomDict.TryGetValue(kvp.Key, out var temp_bomList))
                {
                    bool isExist = false;
                    foreach (var mx in kvp.Value)
                    {
                        isExist = temp_bomList.FindIndex(t => t.mtrlid == mx.mtrlid) > -1;
                    }
                    if (isExist)
                    {
                        // 1
                        foreach (var mx in kvp.Value)
                        {
							mx.printid = newList.Count + 1;
							newList.Add(mx);
                        }
                    }
                    else
                    {
                        // 2.1
                        foreach (var mx in temp_bomList)
                        {
                            mx.printid = newList.Count + 1;
                            newList.Add(mx);
                        }
                    }
                    bomDict.Remove(kvp.Key);
                }
            }
            // 新增的部件
            foreach (var item in bomDict)
			{
                foreach (var mx in item.Value)
                {
                    mx.printid = newList.Count + 1;
                    newList.Add(mx);
                }
            }
            // 2.2
            foreach (var mx in pzid0List)
            {
                mx.printid = newList.Count + 1;
                newList.Add(mx);
            }
			if (newList.Count <= 0) newList.AddRange(bomList);
			return newList;
        }
        /// <summary>
        /// 根据部件配置项值获取对应BOM明细
        /// </summary>
        /// <param name="mxlist"></param>
        /// <param name="codeList"></param>
        public List<u_softbed_mx> GetSoftBedMxBomList(List<u_configure_codemx> codeList)
		{
			var mxlist = new List<u_softbed_mx>();
			foreach(var code in codeList)
			{
				var resultList = new List<u_configure_codemxbom>();
				var outputFields = @"pzid,printid,pid,mtrlid,sonscale,sonscale_formula,mng_cost_rate,profit_rate,realqty,cost,sonloss,sonloss_formula,
									sondecloss,sondecloss_formula,default_length,default_width,default_qty,mtrlcode,mtrlname,mtrlmode,unit,
									mtrlsectype,zxmtrlmode,usermtrlmode,price,pzname";
				var selectStr = @"SELECT u_configure_codemxbom.pzid
										,u_configure_codemxbom.printid
										,u_configure_codemxbom.pid
										,u_configure_codemxbom.mtrlid
										,u_configure_codemxbom.sonscale
										,u_configure_codemxbom.sonscale_formula
										,u_configure_codemxbom.mng_cost_rate
										,u_configure_codemxbom.profit_rate
										,u_configure_codemxbom.realqty
										,u_configure_codemxbom.cost
										,u_configure_codemxbom.sonloss
										,u_configure_codemxbom.sonloss_formula
										,u_configure_codemxbom.sondecloss
										,u_configure_codemxbom.sondecloss_formula
										,u_configure_codemxbom.default_length
										,u_configure_codemxbom.default_width
										,u_configure_codemxbom.default_qty
										,u_mtrldef.mtrlcode
										,u_mtrldef.mtrlname
										,u_mtrldef.mtrlmode
										,u_mtrldef.unit
										,u_mtrldef.mtrlsectype
										,u_mtrldef.zxmtrlmode
										,u_mtrldef.usermtrlmode
										,u_erpmtrl_price.price
										,u_configure_codemx.namemx AS pzname
									FROM u_configure_codemxbom
									INNER JOIN u_configure_codemx ON u_configure_codemxbom.pzid = u_configure_codemx.pzid
										AND u_configure_codemxbom.printid = u_configure_codemx.printid
									INNER JOIN u_mtrldef ON u_configure_codemxbom.mtrlid = u_mtrldef.mtrlid
									LEFT OUTER JOIN u_erpmtrl_price ON u_configure_codemxbom.mtrlid = u_erpmtrl_price.mtrlid";
				DbSqlHelper.SelectJoin(cmd,selectStr, 
					"u_configure_codemxbom.pzid = @pzid AND u_configure_codemxbom.printid = @printid",
					new Dictionary<string, object>() { { "@pzid", code.pzid }, { "@printid",code.printid} }, 
					"u_configure_codemxbom.pid", outputFields, 0,0,resultList);

				foreach(var item in resultList)
				{
					mxlist.Add(InitSoftBedMxFromBom(item, code.has_type.Value));
				}
			}
			return mxlist;
        }
		/// <summary>
		/// 初始化配置项值带出的BOM清单列表
		/// </summary>
		/// <param name="bomItem"></param>
		/// <returns></returns>
		public u_softbed_mx InitSoftBedMxFromBom(u_configure_codemxbom bomItem,byte has_type)
		{
			var mx = new u_softbed_mx()
			{
				pzid = bomItem.pzid,
				mtrlid = bomItem.mtrlid,
				mtrlname = bomItem.mtrlname,
				mtrlcode = bomItem.mtrlcode,
				mtrlmode = bomItem.mtrlmode,
				unit = bomItem.unit,
				allow_edit = 0,
				has_type = has_type, // 1-床头、2-床头柜、4-床架
				cutting_length = bomItem.default_length,
				cutting_width = bomItem.default_width,
				cutting_qty = bomItem.default_qty,
				price = bomItem.price,
				price_formula = "",
				price_formula_str = "",
				useqty = bomItem.sonscale,
				use_formula = "",
				use_formula_str = "",
				actual_useqty = 0,
				loss_rate = bomItem.sonloss,
				cost_price = 0,
				cost_amt = 0,
				pzname = bomItem.pzname
			};
			return mx;
        }
		/// <summary>
		/// 新建/修改 软床报价
		/// </summary>
		/// <param name="softbed"></param>
		/// <exception cref="LJCommonException"></exception>
		public void SaveSoftBed(u_softbed softbed)
		{
			SaveCheck(softbed);
            // 初始化属性
            AutoInit.AutoInitS(softbed);
			foreach(var mx in softbed.mxList)
			{
				AutoInit.AutoInitS(mx);

                if (mx.has_type != 8) mx.parts_type = string.Empty;
                else if (string.IsNullOrEmpty(mx.parts_type)) throw new LJCommonException($"明细行:{mx.printid},存在其他配件明细未设置配件类型,请检查!");
			}
			// 计算价格
			CalCulateFormula(softbed);
            // 
            var dtNow = context.opdate;
			var fields = @"softbed_relcode,softbed_name,deptid,mtrlmode,mtrltype,has_headboard,has_nightstand,has_bedframe,is_template,
                            template_id,template_code,template_name,commission,taxes,taxrate,other_rate,extras_cost,money_type,moneyrate,dscrp,costamt,nottax_factory_cost,nottax_dept_cost,
                            dept_cost,foreign_cost,total_mtrl_cost,total_hr_cost,total_cost,version";

			var mx_fields = @"softbed_id,printid,pzid,formulaid,mtrlid,mtrlname,mtrlcode,mtrlmode,unit,has_type,allow_edit,cutting_length,cutting_width,cutting_qty,
							useqty,use_formula,use_formula_str,actual_useqty,loss_rate,price,price_formula,price_formula_str,cost_price,cost_amt,parts_type,pzname";

			if(softbed.softbed_id == 0)
			{
				// 新建
				fields += ",softbed_id,softbed_code,create_date,create_emp";

                softbed.softbed_id = BllHelper.GetID(cmd, "u_softbed");
                softbed.create_date = dtNow;
                softbed.create_emp = context.tokendata.username;
				softbed.version = 1;

                if (string.IsNullOrEmpty(softbed.softbed_code))
                {
                    // 编号-年月日+流水
                    softbed.softbed_code = $"RC-{dtNow.ToString("yyyyMMdd")}{(softbed.softbed_id % 10000).ToString("D4")}";
                }

                DbSqlHelper.Insert(cmd, "u_softbed", null, softbed, fields);
            } else
			{
				// 修改
				softbed.update_date = dtNow;
				softbed.update_emp = context.tokendata.username;
				softbed.version++;
                fields += ",update_date,update_emp";

                cmd.CommandText = @"DELETE FROM u_softbed_mx WHERE softbed_id = @softbed_id";
                cmd.Parameters.Clear();
                cmd.Parameters.AddWithValue("@softbed_id", softbed.softbed_id);
                cmd.ExecuteNonQuery();

                DbSqlHelper.Update(cmd, "u_softbed", null, softbed, "softbed_id", fields);
            }

            for (int i = 0; i < softbed.mxList.Count; i++)
            {
                var mx = softbed.mxList[i];

                mx.softbed_id = softbed.softbed_id;
				mx.printid = i + 1;

				DbSqlHelper.Insert(cmd, "u_softbed_mx", null, mx, mx_fields);
            }

			SaveSoftBedTemplate(softbed);
            // 解锁
            LockHelper.UnLockBill(cmd, BillKeyWord, softbed.softbed_id, context.tokendata.username, 0);
        }
		private void SaveCheck(u_softbed softbed)
		{
            if (softbed == null) throw new LJCommonException("软床报价保存失败,数据异常!");
            if (softbed.is_template == 0 && (softbed.mxList == null || softbed.mxList.Count <= 0)) throw new LJCommonException("软床报价保存失败，明细内容为空!");

			if(softbed.softbed_id > 0)
            {
                // 检查锁
				if (LockHelper.CheckIsLock(cmd, MattressHelper.BillKeyWord, softbed.softbed_id, context.tokendata.username, out string arg_msg)) throw new LJCommonException(arg_msg);
                // 检测版本控制
                CheckBillVersion<u_softbed>(cmd, softbed.softbed_id, softbed.version);
                //var _softbed = GetSoftBed(softbed.softbed_id, "softbed_id,softbed_code,version,update_emp");
				//if (_softbed.version != softbed.version) throw new LJCommonException($"单据:{_softbed.softbed_code}已被{_softbed.update_emp}修改，请重新加载最新数据再操作!");
			}

			if(softbed.softbed_id > 0 && softbed.is_template != 0)
			{
                // 
				var configureList = GetSoftBedConfigureName(softbed);
                var bomSet = new Dictionary<int,List<u_configure_codemxbom>>();

				foreach(var configure in configureList)
				{
                    cmd.CommandText = @"SELECT u_configure_code.pzid
											,u_configure_codemxbom.mtrlid
											,LTRIM(RTRIM(u_configure_type.contfigtypename))
											,u_configure_type.contfigtypeid
										FROM u_configure_codemxbom
										INNER JOIN u_configure_codemx ON u_configure_codemxbom.pzid = u_configure_codemx.pzid
											AND u_configure_codemxbom.printid = u_configure_codemx.printid
										INNER JOIN u_configure_code ON u_configure_codemx.pzid = u_configure_code.pzid
										INNER JOIN u_configure_type ON u_configure_code.typeid = u_configure_type.contfigtypeid
										WHERE LTRIM(RTRIM(u_configure_type.contfigtypename)) = @contfigtypename";
                    cmd.Parameters.Clear();
                    cmd.Parameters.AddWithValue("@contfigtypename", configure.Value.contfigtypename);
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
							if (!bomSet.ContainsKey(configure.Key)) bomSet.Add(configure.Key, new List<u_configure_codemxbom>());

                            bomSet[configure.Key].Add(new u_configure_codemxbom()
							{
								pzid = Convert.ToInt32(reader["pzid"]),
								mtrlid = Convert.ToInt32(reader["mtrlid"]),
								typeid = Convert.ToInt32(reader["contfigtypeid"]),
								has_type = configure.Key
							});
                        }
                    }
                }
                foreach (var mx in softbed.mxList)
				{
                    if (mx.has_type == 8) continue;
					if(!bomSet.TryGetValue(mx.has_type, out var bomList))
					{
						throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}没有设置物料清单");
					}
					//var cnt = bomList.Where(t => t.has_type == mx.has_type && t.mtrlid == mx.mtrlid).Count();
					//if (cnt > 1) throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}的{mx.mtrlname}存在多个清单,但没有设置部件!");
					//else if (cnt == 0) throw new LJCommonException($"保存失败,原因:{configureList[mx.has_type].contfigtypename}的{mx.mtrlname}不存在于物料清单中,请检查!");
                }
            }
        }
        /// <summary>
        /// 新建软床报价模板
        /// </summary>
        /// <param name="softbed"></param>
        private void SaveSoftBedTemplate(u_softbed softbed)
		{
			if (softbed.is_template == 0) return;

			if(string.IsNullOrEmpty(softbed.softbed_code))
			{
				throw new LJCommonException("报价未生成唯一码,无法生成模板配置");
			}

			string prefix = $"{softbed.softbed_code}|";
			var configureList = GetSoftBedConfigureName(softbed).Values.ToList();

            var baseInfoHelper = GetHelper<BasicInfoHelper>(cmd, context);
			foreach(var configure in configureList)
            {
                // 判断是否已存在
                cmd.CommandText = @"SELECT COUNT(*) FROM u_configure_type WHERE LTRIM(RTRIM(contfigtypename)) = @contfigtypename";
                cmd.Parameters.Clear();
				cmd.Parameters.AddWithValue("@contfigtypename", configure.contfigtypename);
				var cnt = Convert.ToInt32(cmd.ExecuteScalar());

				if (cnt > 0) continue;
                baseInfoHelper.SaveConfigureType(configure);
            }

			// 生成标准选配项值ifdft
			if(softbed.codeMxList != null && softbed.codeMxList.Count > 0)
			{
				foreach (var codeMx in softbed.codeMxList)
                {
					if (codeMx.pzid == 0) continue;
                    // 判断是否有标准
                    cmd.CommandText = @"SELECT COUNT(*) FROM u_configure_codemx WHERE pzid = @pzid AND printid = @printid AND ifdft = 1";
                    cmd.Parameters.Clear();
                    cmd.Parameters.AddWithValue("@pzid", codeMx.pzid);
                    cmd.Parameters.AddWithValue("@printid", codeMx.printid);
					if(Convert.ToInt32(cmd.ExecuteScalar()) > 0)
					{
						cmd.CommandText = @"UPDATE u_configure_codemx SET ifdft = 0 WHERE pzid = @pzid AND printid = @printid AND ifdft = 1";
                        cmd.Parameters.Clear();
                        cmd.Parameters.AddWithValue("@pzid", codeMx.pzid);
                        cmd.Parameters.AddWithValue("@printid", codeMx.printid);
                        cmd.ExecuteNonQuery();
                    }

                    codeMx.ifdft = 1;
                    DbSqlHelper.Update(cmd, "u_configure_codemx", null, codeMx, "pzid,printid", "ifdft");
                }
            }
        }
		/// <summary>
		/// 返回软床报价相关配置名
		/// </summary>
		/// <param name="softbed"></param>
		/// <returns></returns>
		private Dictionary<byte, u_configure_type> GetSoftBedConfigureName(u_softbed softbed)
		{
			var dict = new Dictionary<byte, u_configure_type>();
            string prefix = $"{softbed.softbed_code}|";
            if (softbed.has_headboard == 1)
            {
				dict.Add(1, new u_configure_type()
				{
					contfigtypeid = 0,
					contfigtypename = $"{prefix}床头",
					contfigtype = 0,
					usechflag = 1,
					flag = 0
				});
            }

            if (softbed.has_nightstand == 1)
            {
                dict.Add(2, new u_configure_type()
                {
                    contfigtypeid = 0,
                    contfigtypename = $"{prefix}床头柜",
                    contfigtype = 0,
                    usechflag = 1,
                    flag = 0
                });
            }

            if (softbed.has_bedframe == 1)
            {
                dict.Add(4,new u_configure_type()
                {
                    contfigtypeid = 0,
                    contfigtypename = $"{prefix}床架",
                    contfigtype = 0,
                    usechflag = 1,
                    flag = 0
                });
            }

			return dict;
        }
		/// <summary>
		/// 获取软床报价配置
		/// </summary>
		/// <param name="softbed"></param>
		/// <param name="extraWheres"></param>
		/// <returns></returns>
		public List<u_configure_type> GetSoftBedConfigureList(u_softbed softbed,List<string> extraWheres)
		{
			var codeMxList = new List<u_configure_codemx>();

			var selectStr = @"SELECT u_configure_codemx.pzid
								,u_configure_codemx.printid
								,u_configure_codemx.pzcodemx
								,u_configure_codemx.namemx
								,u_configure_code.name AS pzname
								,u_configure_code.pzcode
								,u_configure_code.inputtype
								,LTRIM(RTRIM(u_configure_type.contfigtypename)) AS contfigtypename
								,u_configure_code.typeid
								,u_configure_codemx.ifdft
							FROM u_configure_codemx
							INNER JOIN u_configure_code ON u_configure_codemx.pzid = u_configure_code.pzid
							INNER JOIN u_configure_type ON u_configure_code.typeid = u_configure_type.contfigtypeid";
			var whereList = new List<string>();
			var nameList = new List<string>();
            if (softbed.softbed_id > 0 || softbed.template_id > 0)
            {
                // 模版配置获取
				int billid = softbed.softbed_id > 0 ? softbed.softbed_id : softbed.template_id;
                var _softbed = GetSoftBed(billid, "softbed_id,softbed_code,has_headboard,has_nightstand,has_bedframe,template_id,is_template");
				if(_softbed.is_template == 0)
				{
                    _softbed = GetSoftBed(_softbed.template_id, "softbed_code,has_headboard,has_nightstand,has_bedframe");
                }
                string prefix = $"{_softbed.softbed_code}|";

				if(_softbed.has_headboard == 1)
				{
					nameList.Add($"{prefix}床头");
                }

                if (_softbed.has_nightstand == 1)
                {
                    nameList.Add($"{prefix}床头柜");
                }

                if (_softbed.has_bedframe == 1)
                {
                    nameList.Add($"{prefix}床架");
                }
            }

			if(nameList.Count > 0)
			{
				whereList.Add($"LTRIM(RTRIM(u_configure_type.contfigtypename)) IN {ListEx.getString(nameList)}");
			}
			if(extraWheres != null && extraWheres.Count > 0)
			{
				whereList.AddRange(extraWheres);
			}
			DbSqlHelper.SelectJoin(cmd, selectStr, ListEx.GetWhereStr(whereList), null, "typeid,pzid,printid", "typeid,pzid,printid,pzcodemx,namemx,pzname,pzcode,contfigtypename,ifdft", 0, 0, codeMxList);

			// 部件选配项
            var codeMap = new Dictionary<int, u_configure_code>();
			foreach(var codeMx in codeMxList)
			{
                int pzid = codeMx.pzid.Value;
                if (!codeMap.TryGetValue(pzid, out var config))
                {
                    config = new u_configure_code
                    {
                        pzid = pzid,
						name = codeMx.pzname,
                        contfigtypename = codeMx.contfigtypename,
						pzcode = codeMx.pzcode,
						typeid = codeMx.typeid,
                        codeMxList = new List<u_configure_codemx>()
                    };

                    codeMap.Add(pzid, config);
                }

                config.codeMxList.Add(codeMx);
            }

			// 部件选配类型
			var typeMap = new Dictionary<int, u_configure_type>();
			foreach(var code in codeMap.Values.ToList())
			{
                int typeid = code.typeid.Value;
                if (!typeMap.TryGetValue(typeid, out var config))
                {
                    config = new u_configure_type
                    {
                        contfigtypeid = typeid,
                        contfigtypename = code.contfigtypename,
                        codeList = new List<u_configure_code>()
                    };

                    typeMap.Add(typeid, config);
                }

                config.codeList.Add(code);
            }

			return typeMap.Values.ToList();
        }
		/// <summary>
		/// 复制软床报价
		/// </summary>
		/// <param name="softbed"></param>
		/// <param name="newId"></param>
        public u_softbed CopySoftBed(u_softbed softbed)
        {
            var softbed_copy = ObjectHelper.DeepCopy(softbed);
            softbed_copy.softbed_id = 0;
            SaveSoftBed(softbed_copy);

            if(softbed_copy.is_template == 1 && softbed.copy_id > 0)
            {
                // 复制配置到新配置
                var _softbed = GetSoftBed(softbed.copy_id, "softbed_code,has_headboard,has_nightstand,has_bedframe");
                if(_softbed.has_headboard == 1 && softbed_copy.has_headboard == 1)
                {
                    CopyConfigureData($"{_softbed.softbed_code}|床头",$"{softbed_copy.softbed_code}|床头");
                }
                if (_softbed.has_nightstand == 1 && softbed_copy.has_nightstand == 1)
                {
                    CopyConfigureData($"{_softbed.softbed_code}|床头柜", $"{softbed_copy.softbed_code}|床头柜");
                }
                if (_softbed.has_bedframe == 1 && softbed_copy.has_bedframe == 1)
                {
                    CopyConfigureData($"{_softbed.softbed_code}|床架", $"{softbed_copy.softbed_code}|床架");
                }
            }

            return softbed_copy;
        }

        /// <summary>
        /// 删除软床报价
        /// </summary>
        /// <param name="billid"></param>
        /// <exception cref="LJCommonException"></exception>
        public void DeleteSoftBed(int billid)
		{
			var softbed = GetSoftBed(billid, "softbed_code,flag");

			if (softbed == null) throw new LJCommonException($"单据不存在,请检查! billid:{billid}");

			if (softbed.flag == 1) throw new LJCommonException($"单据:{softbed.softbed_code}已审核,无法删除!");

			DbSqlHelper.Delete(cmd, softbed);
		}

		/// <summary>
		/// 审核软床报价
		/// </summary>
		/// <param name="billid"></param>
		/// <exception cref="LJCommonException"></exception>
		public void AuditSoftBed(int billid)
        {
            var softbed = GetSoftBed(billid, "softbed_code,flag");

            if (softbed == null) throw new LJCommonException($"单据不存在,请检查! billid:{billid}");

            if (softbed.flag == 1) throw new LJCommonException($"单据:{softbed.softbed_code}未撤审,无法审核!");

			softbed.flag = 1;
			softbed.audit_date = context.opdate;
			softbed.audit_emp = context.tokendata.username;
            DbSqlHelper.Update(cmd, "u_softbed",null,softbed, "softbed_id", "flag,audit_date,audit_emp");
        }

		/// <summary>
		/// 撤审软床报价
		/// </summary>
		/// <param name="billid"></param>
		/// <exception cref="LJCommonException"></exception>
        public void CAuditSoftBed(int billid)
        {
            var softbed = GetSoftBed(billid, "softbed_code,flag");

            if (softbed == null) throw new LJCommonException($"单据不存在,请检查! billid:{billid}");

            if (softbed.flag == 0) throw new LJCommonException($"单据:{softbed.softbed_code}未审核,无法撤审!");

			softbed.flag = 0;
            softbed.audit_date = null;
            softbed.audit_emp = string.Empty;
            DbSqlHelper.Update(cmd, "u_softbed", null, softbed, "softbed_id", "flag,audit_date,audit_emp");
        }

		public void CalCulateFormula(u_softbed softbed)
		{
			InitSoftBed(softbed);
			InitReplaceMents(softbed);

            decimal total_mtrl_cost = 0, total_hr_cost = 0;
            foreach (var mx in softbed.mxList)
			{
                InitMxReplaceMents(softbed, mx);

				formula.CalculateAll();

                // 转换后的文本公式
                mx.use_formula_str = formula.GetFormulaItem("【实际用量】").formula_transform;
                mx.price_formula_str = formula.GetFormulaItem("【成本单价】").formula_transform;

                // 成本单价
                mx.cost_price = formula.GetFormulaItem("【成本单价】").value;
				// 实际用量
				mx.actual_useqty = formula.GetFormulaItem("【实际用量】").value;
                // 成本金额
                mx.cost_amt = formula.GetFormulaItem("【成本金额】").value;
				// 总材料成本
				total_mtrl_cost += mx.cost_amt;
				// 总人力成本
				total_hr_cost += 0;
            }

			if(softbed.mxList != null && softbed.mxList.Count > 0)
			{
                softbed.total_mtrl_cost = total_mtrl_cost;
                softbed.total_hr_cost = total_hr_cost;
                softbed.total_cost = formula.GetFormulaItem("【车间成本】").value;

                softbed.nottax_factory_cost = formula.GetFormulaItem("【不含税出厂价】").value;
                softbed.nottax_dept_cost = formula.GetFormulaItem("【部门不含税价】").value;
                softbed.dept_cost = formula.GetFormulaItem("【部门含税价】").value;
                softbed.taxes = formula.GetFormulaItem("【税金】").value;
                softbed.foreign_cost = formula.GetFormulaItem("【外币价】").value;
            }
            //formula.CalculateAll();
        }

		private void InitSoftBed(u_softbed softbed)
		{
            var dept = Cache.GetData<u_dept, DeptMapping>(softbed.deptid);

			//
            softbed.dept_profitrate = dept.profitrate;

			//
            softbed.moneyrate = softbed.moneyrate <= 0 ? 1 : softbed.moneyrate;
            softbed.commission = softbed.commission <= 0 ? 1 : softbed.commission;
            softbed.taxrate = softbed.taxrate <= 0 ? 1 : softbed.taxrate;
            softbed.other_rate = softbed.other_rate <= 0 ? 1 : softbed.other_rate;
            softbed.dept_profitrate = softbed.dept_profitrate <= 0 ? 1 : softbed.dept_profitrate;

            // 检查佣金是否小于1
            if (softbed.commission < 1)
            {
                throw new LJCommonException("佣金点数不能小于1!");
            }

            // 检查税率是否小于1
            if (softbed.taxrate < 1)
            {
                throw new LJCommonException("税率不能小于1!");
            }

            // 检查额外点数是否小于1
            if (softbed.other_rate < 1)
            {
                throw new LJCommonException("税率不能小于1!");
            }

            // 检查部门利润率是否为0
            if (softbed.dept_profitrate == 0)
            {
                throw new LJCommonException("部门利润率不能为0!");
            }

			if(softbed.is_template == 1)
			{
				// 使用模板报价
				softbed.template_id = 0;
				softbed.template_code = string.Empty;
				softbed.template_name = string.Empty;
			}
        }

		private void InitReplaceMents(u_softbed softbed)
        {
            // 常量变量
            formula.AddFormulaItem("【部门利润率】", softbed.dept_profitrate);
			formula.AddFormulaItem("【佣金点数】", softbed.commission);
			formula.AddFormulaItem("【额外点数】", softbed.other_rate);
			formula.AddFormulaItem("【额外费用】", softbed.extras_cost);
			formula.AddFormulaItem("【汇率】", softbed.moneyrate);
			formula.AddFormulaItem("【税率】", softbed.taxrate);
            formula.AddFormulaItem("【工厂利润率】", 1);
            formula.AddFormulaItem("【FOB】", 0);
			formula.AddFormulaItem("【外销加点】", 0);
            formula.AddFormulaItem("【总材料成本】", softbed.total_mtrl_cost);
            formula.AddFormulaItem("【总人力成本】", softbed.total_hr_cost);

            // 公式变量
            formula.AddFormulaItem("【不含税出厂价】", "【车间成本】*(【工厂利润率】+【外销加点】)");
            formula.AddFormulaItem("【部门不含税价】", "【不含税出厂价】/【部门利润率】/( 1 - (【佣金点数】- 1))*【额外点数】+【FOB】");
            formula.AddFormulaItem("【部门含税价】", "【部门不含税价】*【税率】");
            formula.AddFormulaItem("【税金】", "【部门不含税价】* (【税率】-1)");
            formula.AddFormulaItem("【外币价】", "【部门含税价】/【汇率】");
        }

        private void InitMxReplaceMents(u_softbed softbed,u_softbed_mx mx)
        {
			// 默认公式变量
			formula.AddFormulaItem("【车间成本】", "【总材料成本】 + 【总人力成本】 + 【额外费用】");
            formula.AddFormulaItem("【成本单价】", "【材料单价】*1");
            formula.AddFormulaItem("【实际用量】", "【用料量】*(1 + 【损耗率】)");
            formula.AddFormulaItem("【成本金额】", "【实际用量】 * 【成本单价】");

            // 常量变量
            formula.AddFormulaItem("【下料长】", mx.cutting_length);
            formula.AddFormulaItem("【下料宽】", mx.cutting_width);
            formula.AddFormulaItem("【下料数量】", mx.cutting_qty);
            formula.AddFormulaItem("【用料量】", mx.useqty);
            formula.AddFormulaItem("【损耗率】", mx.loss_rate);
            formula.AddFormulaItem("【材料单价】", mx.price);

			if(mx.formulaid > 0)
			{
				cmd.CommandText = @"SELECT u_softbed_formula.formulaid
										,u_softbed_formula.formulaname
										,u_softbed_formula.use_formula
										,u_softbed_formula.price_formula
									FROM u_softbed_formula
									WHERE formulaid = @formulaid";
				cmd.Parameters.Clear();
				cmd.Parameters.AddWithValue("@formulaid", mx.formulaid);
				using(var reader = cmd.ExecuteReader())
				{
					if(reader.Read())
					{
                        formula.AddFormulaItem("【实际用量】", Convert.ToString(reader["use_formula"]));
                        formula.AddFormulaItem("【成本单价】", Convert.ToString(reader["price_formula"]));
                    }
				}
			}
        }

        private List<string> GetConfigureTypeNameFromBillId(int billid)
        {
            var _softbed = GetSoftBed(billid, "softbed_code,has_headboard,has_nightstand,has_bedframe");

            var nameList = new List<string>();
            string prefix = $"{_softbed.softbed_code}|";
            if (_softbed.has_headboard == 1)
            {
                nameList.Add($"{_softbed.softbed_code}|床头");
            }
            if (_softbed.has_nightstand == 1)
            {
                nameList.Add($"{_softbed.softbed_code}|床头柜");
            }
            if (_softbed.has_bedframe == 1)
            {
                nameList.Add($"{_softbed.softbed_code}|床架");
            }

            return nameList;
        }

        private void CopyConfigureData(string SourceName, string TargetName)
        {
            var commonHelper = GetHelper<CommonHelper>(cmd, context);
            var basicInfoHelper = GetHelper<BasicInfoHelper>(cmd, context);
            // 入参非空验证
            if (string.IsNullOrWhiteSpace(SourceName))
            {
                throw new LJCommonException("源配置名称不能为空");
            }

            if (string.IsNullOrWhiteSpace(TargetName))
            {
                throw new LJCommonException("目标配置名称不能为空");
            }

            int SourceId = 0, TargetId = 0;
            cmd.CommandText = @"SELECT contfigtypeid FROM u_configure_type WHERE LTRIM(RTRIM(contfigtypename)) = LTRIM(RTRIM(@SourceName))";
            cmd.Parameters.Clear();
            cmd.Parameters.AddWithValue("@SourceName", SourceName);
            using(var reader = cmd.ExecuteReader())
            {
                if(reader.Read())
                {
                    SourceId = Convert.ToInt32(reader["contfigtypeid"]);
                }
            }

            cmd.CommandText = @"SELECT contfigtypeid FROM u_configure_type WHERE LTRIM(RTRIM(contfigtypename)) = LTRIM(RTRIM(@TargetName))";
            cmd.Parameters.Clear();
            cmd.Parameters.AddWithValue("@TargetName", TargetName);
            using (var reader = cmd.ExecuteReader())
            {
                if (reader.Read())
                {
                    TargetId = Convert.ToInt32(reader["contfigtypeid"]);
                }
            }

            if (SourceId == 0) throw new LJCommonException($"源配置名称「{SourceName.Trim()}」未找到对应的结果");
            if (TargetId == 0) throw new LJCommonException($"目标配置名称「{TargetName.Trim()}」未找到对应的结果");
            // 部件选配项
            var codeList = commonHelper.ExecuteDynamicSelectToList<u_configure_code>("web_configure_codelist",new Newtonsoft.Json.Linq.JObject() { { "typeid",SourceId} },0,0);
            var code_copyList = new List<u_configure_code>();
            var codeIdMap = new Dictionary<int, int>();
            foreach(var code in codeList)
            {
                var code_copy = ObjectHelper.DeepCopy(code);
                code_copy.pzid = BllHelper.GetID(cmd, "u_configure_code");
                code_copy.typeid = TargetId;
                code_copyList.Add(code_copy);

                if (codeIdMap.ContainsKey(code.pzid.Value)) continue;
                codeIdMap.Add(code.pzid.Value, code_copy.pzid.Value);
                //basicInfoHelper.SaveConfigureCode(code_copy);
            }
            DbSqlHelper.BulkInsert(cmd, code_copyList, "u_configure_code", null, "typeid,pzid,pzcode,inputtype,name,configtype,ifcross,ifcheck,ifuse,rulestr,ifnum,decnum,maxnum,minnum,pricestr,priceratestr,ifpack,zj_special");
            // 部件选配值
            var codeMxList = commonHelper.ExecuteDynamicSelectToList<u_configure_codemx>("web_configure_codemxlist", new Newtonsoft.Json.Linq.JObject() { { "typeid", SourceId } }, 0, 0);
            var codeMx_copyList = new List<u_configure_codemx>();
            foreach (var codeMx in codeMxList)
            {
                if (!codeIdMap.TryGetValue(codeMx.pzid.Value, out int newId)) continue;
                var codeMx_copy = ObjectHelper.DeepCopy(codeMx);
                codeMx_copy.pzid = newId;
                codeMx_copyList.Add(codeMx_copy);
            }
            DbSqlHelper.BulkInsert(cmd, codeMx_copyList, "u_configure_codemx",null, "pzid,printid,pzcodemx,namemx,gradestr,mtrlcode,price,ifdft,MCostRate,ProfitRate,dscrp,ifuse,ifnoch,pricerate,packqty,packvol,price_pz,grade");
            // 部件选配物料清单
            var codeMxBomList = commonHelper.ExecuteDynamicSelectToList<u_configure_codemxbom>("web_configure_codemxbomlist", new Newtonsoft.Json.Linq.JObject() { { "typeid", SourceId } }, 0, 0);
            var codeMxBom_copyList = new List<u_configure_codemxbom>();
            foreach (var codeMxBom in codeMxBomList)
            {
                if (!codeIdMap.TryGetValue(codeMxBom.pzid, out int newId)) continue;
                var codeMxBom_copy = ObjectHelper.DeepCopy(codeMxBom);
                codeMxBom_copy.pzid = newId;
                codeMxBom_copyList.Add(codeMxBom_copy);
            }
            DbSqlHelper.BulkInsert(cmd, codeMxBom_copyList, "u_configure_codemxbom",null, "pzid,printid,pid,mtrlid,sonscale,sonscale_formula,mng_cost_rate,profit_rate,realqty,sonloss,sonloss_formula,sondecloss,sondecloss_formula,default_length,default_width,default_qty");
        }

        #region 通用公式
        private CalculateFormula formula = new CalculateFormula();
		private string BillKeyWord = "u_softbed";
        #endregion
    }
}
