using AMESCoreStudio.CommonTools.Result;
using AMESCoreStudio.WebApi.Controllers.BLL;
using AMESCoreStudio.WebApi.DTO.AMES;
using AMESCoreStudio.WebApi.Enum;
using AMESCoreStudio.WebApi.Models.AMES;
using AMESCoreStudio.WebApi.Models.BAS;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using AMESCoreStudio.WebApi.Extensions;

namespace AMESCoreStudio.WebApi.Controllers.AMES
{
    /// <summary>
    /// 過站判斷
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class BarCodeCheckController : ControllerBase
    {
        private readonly AMESContext _context;
        private readonly IConfiguration _config;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public BarCodeCheckController(AMESContext context, IConfiguration config)
        {
            _config = config;
            _context = context;
        }

        #region 過站判斷
        /// <summary>
        /// 過站判斷
        /// </summary>
        /// <param name="barCodeCheckDto"></param>
        /// <returns></returns>
        [HttpPost("PassIngByCheck")]
        public async Task<ActionResult<ResultModel<string>>> CheckBarCodeCheck([FromBody] BarCodeCheckDto barCodeCheckDto)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            try
            {
                // 確認過站欄位是否填寫
                resultModel.Msg = CheckBarCodeInputData(barCodeCheckDto);
                if (!string.IsNullOrWhiteSpace(resultModel.Msg))
                    return resultModel;

                // 抓取過站需要訊息及資料轉換
                var data = await PassIngDataTuck(barCodeCheckDto);

                // 確認資料正確
                resultModel.Msg = await CheckPassIngDataCorrect(data);
                if (!string.IsNullOrWhiteSpace(resultModel.Msg))
                    return resultModel;

                #region 宣告參數
                // 存放要更新BarCodeItem
                var update_BarCodeItem = new List<BarcodeItem>();
                var insert_BarCodeItemChange = new List<BarcodeItemChange>();
                #endregion

                #region 判斷工單狀態

                resultModel = await CheckWipNoSationAsync(wipNo: data.wipNo, unitNo: data.unitNo
                               , flowRuleID: data.flowRule, line: data.line, stationID: data.stationID, barCodeNo: data.barcode);
                if (!resultModel.Success)
                    return resultModel;

                #endregion

                #region 判斷序號區間

                resultModel = await CheckBarCodeByWipNo_New(wipNo: data.wipNo, barcode: data.barcode);
                if (!resultModel.Success)
                    return resultModel;

                #endregion

                #region 判斷序號狀態

                resultModel = await GetCheckBarCodeStation(barCode: data.barcodeID, barCodeNo: data.barcode);
                if (!resultModel.Success)
                    return resultModel;

                #endregion

                #region 判斷序號流程

                resultModel = await CheckBarCodeFlowNew(wipNo: data.wipNo, unitNo: data.unitNo, barCodeId: data.barcodeID,
                                                        barCodeNo: data.barcode, stationId: data.stationID);
                if (!resultModel.Success)
                    return resultModel;

                #endregion

                #region 燒機判斷

                // Station_Type = B 燒機站
                if (data.stations_TypeNo == "B")
                {
                    resultModel = await GetCheckBurn(data.wipNo, data.barcodeID, data.stationID, data.ruleStatus);
                    if (!resultModel.Success)
                        return resultModel;
                    else if (resultModel.Msg == "BurnIn")
                        data.burnIn = true;
                }
                #endregion

                #region SMT 過站刷鋼板編號及錫膏編號 及 治具判斷

                if (data.stations_Name.Contains("SMT"))
                {
                    // 先移除
                    //resultModel = CheckSmtSkip(data);
                    //if (!resultModel.Success)
                    //    return resultModel;
                }
                else
                {
                    resultModel = CheckBarCodeOutfit(data.outfits);
                    if (!resultModel.Success)
                        return resultModel;
                }

                #endregion

                #region KeyParts 判斷

                // 排除刷不良代碼
                if (data.inputItems.Where(w => !w.inputType.ToUpper().StartsWith("NG")).Any())
                {
                    // 
                    var WipKps = _context.WipKps.Where(w => w.WipNo == data.wipNo).OrderBy(o => o.KpSeq).ToList();
                    if (WipKps.Count == 0)
                    {
                        resultModel.Msg = "工單號碼【" + data.wipNo + "】找不到相關Key Parts設定";
                        resultModel.Success = false;
                        return resultModel;
                    }

                    // 一般過站
                    if (data.barcodeType != "S")
                    {
                        var barcodeItemKPDto = new BarcodeItemKPDto
                        {
                            wipNo = data.wipNo,
                            wipId = data.wipID,
                            barCode = data.barcodeID,
                            barCodeNo = data.barcode,
                            unitNo = data.unitNo,
                            ststionUnitNo = data.unitNo,
                            inputKP = data.inputItems.Where(w => !w.inputType.ToUpper().StartsWith("NG")).ToList()
                        };

                        var resultModelKeyParts = await CheckBarCodeKeyPartsData(barcodeItemKPDto);
                        if (!resultModelKeyParts.Success)
                        {
                            resultModel.Success = false;
                            resultModel.Msg = resultModelKeyParts.Msg;
                            return resultModel;
                        }
                        else
                        {
                            // WipKp 更新長度
                            data.UpdateWipKpLenght = resultModelKeyParts.Data.ToList();
                        }

                    }
                    // 維修過站 
                    else if (data.barcodeType == "S")
                    {
                        // 用BarCodeID And WipID 取BarCodeItem
                        var q_BarCodeItem = await _context.BarcodeItems.Where(w => w.BarcodeID == data.barcodeID).ToListAsync();

                        foreach (var KPs in data.inputItems)
                        {
                            // 用舊組件序號比對
                            var barCodeItem = q_BarCodeItem.Where(w => w.PartNo == KPs.oldInputData).FirstOrDefault();

                            if (barCodeItem != null)
                            {
                                var q_Kp = WipKps.Where(w => w.KpNo.ToUpper() == barCodeItem.ItemNo.ToUpper()).FirstOrDefault();
                                if (q_Kp != null)
                                {
                                    resultModel.Msg += await CheckKeyPartsCorrect(q_Kp, KPs);
                                }

                                barCodeItem.WipID = data.wipID;
                                barCodeItem.PartNo = KPs.inputData;
                                barCodeItem.UpdateDate = DateTime.Now;
                                update_BarCodeItem.Add(barCodeItem);

                                insert_BarCodeItemChange.Add(new BarcodeItemChange
                                {
                                    WipID = data.wipID,
                                    StationID = data.stationID,
                                    BarcodeID = data.barcodeID,
                                    ItemNo = barCodeItem.ItemNo,
                                    PartNoOld = KPs.oldInputData,
                                    ChangeType = "RP",
                                    KpItemNo = KPs.inputData,
                                    CreateUserID = data.userID
                                });
                            }
                            else
                            {
                                resultModel.Msg = $"內部條碼【{data.barcode}】找不到已綁定Kp序號【{KPs.oldInputData}】";
                            }
                        }

                        if (!string.IsNullOrWhiteSpace(resultModel.Msg))
                        {
                            resultModel.Success = false;
                            return resultModel;
                        }

                        // 將InputItem清空
                        data.inputItems = new List<BarCodeCheckDto.inputItem>();
                    }
                }
                #endregion

                #region 判斷為CHECK站.組件是否都有資料

                // 判斷作業站是否為CHECK站 Station_Type == C
                if (data.stations_TypeNo == "C")
                {
                    // 過站輸入組件數量
                    var inputKPQty = data.inputItems.Where(w => !w.inputData.Contains("$")).Count();

                    // 已記錄組件數量
                    var BarCodeItems = _context.BarcodeItems.Where(w => w.BarcodeID == data.barcodeID && w.WipID == data.wipID);
                    var Stations = _context.Stationses.Where(w => w.UnitNo == data.unitNo);
                    var BarCodeItemsQty = BarCodeItems.Where(w => Stations.Any(s => s.StationID == w.StationID)).Count();

                    // WipKp DB 設定綁定組件數量 + 製程判斷
                    var wipKpQty = _context.WipKps.Where(w => w.WipNo == data.wipNo
                                                           && w.UnitNo == data.unitNo
                                                           ).Count();

                    if (wipKpQty != inputKPQty + BarCodeItemsQty)
                    {
                        resultModel.Success = false;
                        resultModel.Msg = "組件資料筆數不符,請確認";
                        return resultModel;
                    }
                }

                #endregion

                #region 內部序號輸入後新增 or 更新

                var result_CUTableMsg = await CU_Tables(data);
                if (!string.IsNullOrWhiteSpace(result_CUTableMsg))
                {
                    resultModel.Msg = "內部序號【" + barCodeCheckDto.barcode + "】 過站失敗,錯誤訊息:<br/>";
                    resultModel.Msg += result_CUTableMsg;
                    resultModel.Success = false;
                    return resultModel;
                }

                #endregion

                #region 維修組件更換

                if (update_BarCodeItem.Count() != 0)
                {
                    await UpdateBarCodeItemChange(update_BarCodeItem, insert_BarCodeItemChange);
                }

                #endregion

                #region 燒機In 修改狀態
                if (data.burnIn)
                {
                    resultModel.Msg = $"內部序號【{data.barcode}】 燒機In 完成!";
                }
                else
                {
                    resultModel.Msg = $"內部序號【{data.barcode}】 過站完成!";
                }
                #endregion

                resultModel.Success = true;
                return resultModel;

            }
            catch (Exception ex)
            {
                resultModel.Success = false;
                resultModel.Msg = ex.Message;
                return resultModel;
            }
        }
        #endregion

        #region FQC抽驗過站
        /// <summary>
        /// FQC抽驗過站
        /// </summary>
        /// <param name="inhouseNo">入庫單號</param>
        /// <param name="seqID">順序</param>
        /// <param name="userID">UserID</param>
        /// <returns></returns>
        [HttpGet("PassIngByFQC")]
        public async Task<ActionResult<ResultModel<string>>> PassingByFQC(string inhouseNo, int seqID, int userID)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            var InhouseMaster = _context.FqcInhouseMasters.Where(w => w.InhouseNo == inhouseNo && w.SeqID == seqID)
                                                                .FirstOrDefault();
            try
            {
                if (InhouseMaster != null)
                {
                    //// 判斷是否有設定FQC站 Station_Type == F
                    var WipInfo = _context.WipInfos.Where(w => w.WipNO == InhouseMaster.WipNo &&
                                                               w.UnitNO == InhouseMaster.UnitNo).FirstOrDefault();
                    var RuleStations = _context.RuleStations.Where(w => w.FlowRuleID == WipInfo.FlowRuleID &&
                                                                       w.Station.TypeNo == "F").ToList();
                    // 有設定FQC站別
                    if (RuleStations.Count() != 0)
                    {
                        var RuleStation = RuleStations.FirstOrDefault();
                        BarCodeCheckDtoForDBData data = new BarCodeCheckDtoForDBData();
                        data.line = -1;
                        data.ruleStatus = "P";
                        data.stationID = RuleStation.Station.StationID;
                        data.userID = userID;
                        data.barcodeType = "M";
                        data.UpdateWipKpLenght = new List<WipKp>();
                        // 生產單位_簡碼
                        data.factoryUnit_UnitCode = _context.FactoryUnits.Where(w => w.UnitNo == WipInfo.UnitNO).FirstOrDefault().UnitCode ?? "";

                        var BarcodeNo = new List<BarcodeInfo>();

                        // 取FQC抽驗單號 
                        var InhouseDetail = _context.FqcInhouseDetails.Where(w => w.InhouseNo == inhouseNo && w.SeqID == seqID)
                                                                       .ToList();
                        // 有序號開入庫單
                        if (InhouseDetail.Count != 0)
                        {
                            foreach (var item in InhouseDetail.Select(s => s.SerialNo).Distinct())
                            {
                                BarcodeNo = _context.BarcodeInfoes.Where(w => w.BoxNo == item).ToList();
                                //// 用箱號抽驗
                                //if (item.SerialType == "B")
                                //{
                                //    BarcodeNo = _context.BarcodeInfoes.Where(w => w.BoxNo == item.SerialNo).ToList();
                                //}
                                //// 條碼
                                //else
                                //{
                                //    BarcodeNo = await _context.BarcodeInfoes.Where(w => w.BarcodeNo == item.SerialNo &&
                                //                                                        w.WipID == WipInfo.WipID).ToListAsync();
                                //}

                                foreach (var barcode in BarcodeNo)
                                {
                                    data.unitNo = WipInfo.UnitNO;
                                    data.wipID = barcode.WipID;
                                    data.barcode = barcode.BarcodeNo;
                                    data.barcodeID = barcode.BarcodeID;
                                    data.extNo = barcode.ExtraBarcodeNo;
                                    data.flowRule = WipInfo.FlowRuleID;
                                    data.wipNo = WipInfo.WipNO;

                                    var result_CUTableMsg = await CU_Tables(data);
                                    if (string.IsNullOrWhiteSpace(result_CUTableMsg))
                                    {
                                        resultModel.Success = true;
                                        resultModel.Msg = "FQC過站完成";
                                    }
                                    else
                                    {
                                        resultModel.Msg = result_CUTableMsg;
                                    }
                                }
                            }
                        }
                        // 無序號直接用入庫數量取BarCodeInfo尚未結束的
                        else
                        {
                            // 例外 包裝站為第一站就不會有過站紀錄 直接FQC完成就好
                            if (_context.Ruleses.Where(w => w.NextStationID == data.stationID && w.RuleSeq == 1 && w.FlowRuleID == WipInfo.FlowRuleID).Any())
                            {
                                resultModel.Success = true;
                                return resultModel;
                            }

                            // 找FQC的上上一站(因為不會過包裝站)
                            var rules = await _context.Ruleses.Where(w => w.FlowRuleID == WipInfo.FlowRuleID).ToListAsync();
                            // FQC的上一站
                            var rulesFqcUpStation = rules.Where(w => w.NextStationID == data.stationID).Select(s => s.StationID).ToList();
                            rules = rules.Where(w => rulesFqcUpStation.Contains(w.NextStationID)).ToList();
                            if (rules.Count != 0)
                            {
                                var nextStations = rules.Select(s => s.StationID).ToList();
                                BarcodeNo = await _context.BarcodeInfoes.Where(w => w.WipID == WipInfo.WipID &&
                                                                                    nextStations.Contains(w.StationID) &&
                                                                                    w.StatusID == 1).ToListAsync();
                                if (BarcodeNo.Count != 0)
                                {
                                    foreach (var barcode in BarcodeNo.OrderBy(o => o.BarcodeNo).Take(InhouseMaster.InhouseQty))
                                    {
                                        data.unitNo = WipInfo.UnitNO;
                                        data.wipID = barcode.WipID;
                                        data.barcode = barcode.BarcodeNo;
                                        data.barcodeID = barcode.BarcodeID;
                                        data.extNo = barcode.ExtraBarcodeNo;
                                        data.flowRule = WipInfo.FlowRuleID;
                                        data.wipNo = WipInfo.WipNO;

                                        var result_CUTableMsg = await CU_Tables(data);
                                        if (string.IsNullOrWhiteSpace(result_CUTableMsg))
                                        {
                                            resultModel.Success = true;
                                            resultModel.Msg = "FQC過站完成";
                                        }
                                        else
                                        {
                                            resultModel.Msg = result_CUTableMsg;
                                        }
                                    }
                                }
                                else
                                    resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,找不到有資料可以過站";
                            }
                            else
                            {
                                resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,找不到設定FQC的上上一個作業站";
                            }
                        }
                    }
                    else
                    {
                        resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,無設定FQC站別";
                    }
                }
                else
                {
                    resultModel.Msg = "找不到該筆FQC單號";
                }
                return resultModel;
            }
            catch (Exception ex)
            {
                resultModel.Msg = ex.Message;
                resultModel.Success = false;
                return resultModel;
            }
        }
        #endregion

        #region FQC抽驗過站 NEW
        /// <summary>
        /// FQC抽驗過站
        /// </summary>
        /// <param name="inhouseNo">入庫單號</param>
        /// <param name="seqID">順序</param>
        /// <param name="userID">UserID</param>
        /// <returns></returns>
        [HttpGet("PassIngByFQCV1")]
        public async Task<ActionResult<ResultModel<string>>> PassingByFQCV1(string inhouseNo, int seqID, int userID)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            var InhouseMaster = _context.FqcInhouseMasters.Where(w => w.InhouseNo == inhouseNo && w.SeqID == seqID)
                                                                .FirstOrDefault();
            try
            {
                if (InhouseMaster != null)
                {
                    //// 判斷是否有設定FQC站 Station_Type == F
                    var WipInfo = _context.WipInfos.Where(w => w.WipNO == InhouseMaster.WipNo &&
                                                               w.UnitNO == InhouseMaster.UnitNo).FirstOrDefault();
                    var RuleStations = _context.RuleStations.Where(w => w.FlowRuleID == WipInfo.FlowRuleID &&
                                                                       w.Station.TypeNo == "F").ToList();
                    // 有設定FQC站別
                    if (RuleStations.Count() != 0)
                    {
                        var RuleStation = RuleStations.FirstOrDefault();
                        var datas = new List<BarCodeCheckDtoForDBData>();
                        var BarcodeNo = new List<BarcodeInfo>();

                        // 取FQC抽驗單號 
                        var InhouseDetail = _context.FqcInhouseDetails.Where(w => w.InhouseNo == inhouseNo && w.SeqID == seqID)
                                                                       .ToList();
                        // 有序號開入庫單
                        if (InhouseDetail.Count != 0)
                        {
                            foreach (var item in InhouseDetail.Select(s => s.SerialNo).Distinct())
                            {
                                BarcodeNo = _context.BarcodeInfoes.Where(w => w.BoxNo == item).ToList();
                                //// 用箱號抽驗
                                //if (item.SerialType == "B")
                                //{
                                //    BarcodeNo = _context.BarcodeInfoes.Where(w => w.BoxNo == item.SerialNo).ToList();
                                //}
                                //// 條碼
                                //else
                                //{
                                //    BarcodeNo = await _context.BarcodeInfoes.Where(w => w.BarcodeNo == item.SerialNo &&
                                //                                                        w.WipID == WipInfo.WipID).ToListAsync();
                                //}

                                foreach (var barcode in BarcodeNo)
                                {
                                    var dataItem = new BarCodeCheckDtoForDBData();
                                    dataItem.line = (int)WipInfo.LineID;
                                    dataItem.ruleStatus = "P";
                                    dataItem.stationID = RuleStation.Station.StationID;
                                    dataItem.userID = userID;
                                    dataItem.barcodeType = "M";
                                    dataItem.unitNo = WipInfo.UnitNO;
                                    dataItem.wipID = barcode.WipID;
                                    dataItem.barcode = barcode.BarcodeNo;
                                    dataItem.barcodeID = barcode.BarcodeID;
                                    dataItem.extNo = barcode.ExtraBarcodeNo;
                                    dataItem.flowRule = WipInfo.FlowRuleID;
                                    dataItem.wipNo = WipInfo.WipNO;
                                    datas.Add(dataItem);
                                }
                            }

                            if (datas.Any())
                            {
                                var result_CUTableMsg = await CU_TablesByFQC(datas);
                                if (string.IsNullOrWhiteSpace(result_CUTableMsg))
                                {
                                    resultModel.Success = true;
                                    resultModel.Msg = "FQC過站完成";
                                }
                                else
                                {
                                    resultModel.Msg = result_CUTableMsg;
                                }
                            }
                        }
                        // 無序號直接用入庫數量取BarCodeInfo尚未結束的
                        else
                        {
                            var stationID = RuleStation.Station.StationID;
                            // 例外 包裝站為第一站就不會有過站紀錄 直接FQC完成就好
                            if (_context.Ruleses.Where(w => w.NextStationID == stationID && w.RuleSeq == 1 && w.FlowRuleID == WipInfo.FlowRuleID).Any())
                            {
                                resultModel.Success = true;
                                return resultModel;
                            }

                            // 找FQC的上上一站(因為不會過包裝站)
                            var rules = await _context.Ruleses.Where(w => w.FlowRuleID == WipInfo.FlowRuleID).ToListAsync();
                            // FQC的上一站
                            var rulesFqcUpStation = rules.Where(w => w.NextStationID == stationID).Select(s => s.StationID).ToList();
                            rules = rules.Where(w => rulesFqcUpStation.Contains(w.NextStationID)).ToList();
                            if (rules.Count != 0)
                            {
                                var nextStations = rules.Select(s => s.StationID).ToList();
                                BarcodeNo = await _context.BarcodeInfoes.Where(w => w.WipID == WipInfo.WipID &&
                                                                                    nextStations.Contains(w.StationID) &&
                                                                                    w.StatusID == 1).ToListAsync();
                                if (BarcodeNo.Count != 0)
                                {
                                    foreach (var barcode in BarcodeNo.OrderBy(o => o.BarcodeNo).Take(InhouseMaster.InhouseQty))
                                    {
                                        var dataItem = new BarCodeCheckDtoForDBData();
                                        dataItem.line = (int)WipInfo.LineID;
                                        dataItem.ruleStatus = "P";
                                        dataItem.stationID = RuleStation.Station.StationID;
                                        dataItem.userID = userID;
                                        dataItem.barcodeType = "M";
                                        dataItem.unitNo = WipInfo.UnitNO;
                                        dataItem.wipID = barcode.WipID;
                                        dataItem.barcode = barcode.BarcodeNo;
                                        dataItem.barcodeID = barcode.BarcodeID;
                                        dataItem.extNo = barcode.ExtraBarcodeNo;
                                        dataItem.flowRule = WipInfo.FlowRuleID;
                                        dataItem.wipNo = WipInfo.WipNO;

                                        datas.Add(dataItem);
                                    }

                                    if (datas.Any())
                                    {
                                        var result_CUTableMsg = await CU_TablesByFQC(datas);
                                        if (string.IsNullOrWhiteSpace(result_CUTableMsg))
                                        {
                                            resultModel.Success = true;
                                            resultModel.Msg = "FQC過站完成";
                                        }
                                        else
                                        {
                                            resultModel.Msg = result_CUTableMsg;
                                        }
                                    }
                                }
                                else
                                    resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,找不到有資料可以過站";
                            }
                            else
                            {
                                resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,找不到設定FQC的上上一個作業站";
                            }
                        }
                    }
                    else
                    {
                        resultModel.Msg = $"該筆工單號碼【{InhouseMaster.WipNo}】,無設定FQC站別";
                    }
                }
                else
                {
                    resultModel.Msg = "找不到該筆FQC單號";
                }
                return resultModel;
            }
            catch (Exception ex)
            {
                resultModel.Msg = ex.Message;
                resultModel.Success = false;
                return resultModel;
            }
        }
        #endregion

        #region 判斷過站完成新增or更新 Table
        /// <summary>
        /// 判斷過站完成新增or更新 Table
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task<string> CU_Tables(BarCodeCheckDtoForDBData data)
        {
            #region 先取得各個Table ID

            Helper helper = new Helper(_context);
            int BarCodeId = 0;
            List<int> BarCodeItemId = new List<int>();
            List<int> BarCodeOutfitId = new List<int>();
            int NgId = 0;
            List<int> ComponentId = new List<int>();

            // BarCodeInfo ID
            if (data.barcodeID == 0)
            {
                BarCodeId = helper.GetIDKey("BARCODE_ID").Result;
                data.barcodeID = BarCodeId;
            }

            // 組件料號
            foreach (var item in data.inputItems.Where(w => !w.inputData.Contains("$")))
            {
                BarCodeItemId.Add(helper.GetIDKey("BARCODEITEM_ID").Result);
            }

            // 治具編號
            foreach (var item in data.outfits)
            {
                BarCodeOutfitId.Add(helper.GetIDKey("BARCODE_OUTFIT_ID").Result);
            }

            // 不良代碼
            if (data.inputItems.Where(w => w.inputData.Contains("$")).Any())
            {
                NgId = helper.GetIDKey("NG_ID").Result;
                foreach (var item in data.inputItems.Where(w => w.inputData.Contains("$")))
                {
                    ComponentId.Add(helper.GetIDKey("COMPONENT_ID").Result);
                }
            }

            #endregion

            string Msg = string.Empty;

            using (var tran = _context.Database.BeginTransaction())
            {
                try
                {
                    if (!data.burnIn)
                    {
                        // 條碼主檔
                        Msg = Table_BarcodeInfo(data, BarCodeId);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"BarcodeInfo_Error:{Msg}");
                        }

                        // 條碼紀錄
                        Msg = Table_BarcodeWip(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"BarcodeWip_Error:{Msg}");
                        }

                        // 工單各站數量資料檔
                        Msg = Table_WipStation(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"WipStation_Error:{Msg}");
                        }

                        // 各班別數量資料檔
                        Msg = Table_WipClass(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"WipClass_Error:{Msg}");
                        }

                        // 工單各站數量資料檔 – By TIME
                        Msg = Table_WipTime(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"WipTime_Error:{Msg}");
                        }

                        // 條碼過站資料檔
                        Msg = Table_BarcodeStation(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"BarcodeStation_Error:{Msg}");
                        }

                        // 組件资料
                        Msg = Table_BarcodeItem(data, BarCodeItemId);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"BarcodeItem_Error:{Msg}");
                        }

                        // 條碼治具
                        Msg = Table_BarcodeOutfit(data, BarCodeOutfitId);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"BarcodeOutfit_Error:{Msg}");
                        }

                        // 設備資料檔 使用次數
                        Msg = await Table_OutfitInfo(data);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"OutfitInfo_Error:{Msg}");
                        }

                        // 不良資料檔
                        Msg = Table_NgInfo(data, NgId, ComponentId);
                        if (!string.IsNullOrWhiteSpace(Msg))
                        {
                            throw new Exception($"NgInfo_Error:{Msg}");
                        }

                        // WipKp長度新增 與工單第一筆子件長度相同
                        if (data.UpdateWipKpLenght != null)
                        {
                            if (data.UpdateWipKpLenght.Count != 0)
                            {
                                Msg = Table_WipKps(data.UpdateWipKpLenght, data.userID);
                                if (!string.IsNullOrWhiteSpace(Msg))
                                {
                                    throw new Exception($"WipKps_Error:{Msg}");
                                }
                            }
                        }

                        //// 過站為PASS狀態
                        //if (data.ruleStatus == "P")
                        //{
                        // 判斷是否為第一站
                        if (await CheckNowFirstStation(data.wipID, data.stationID) == "Y")
                        {
                            // 在BarStation 確認該筆工單ID只有一筆當第一次投入
                            var CheckBarcodeStation = await _context.BarcodeStation.Where(w => w.BarcodeID == data.barcodeID &&
                                                                                               w.WipID == data.wipID)
                                                                                   .ToListAsync();
                            if (CheckBarcodeStation.Count() == 1)
                            {
                                // 有資料加1 後續判斷第一次過站
                                string updateSql = $@" UPDATE JHAMES.WIP_INFO SET COMPLETE_QTY = COMPLETE_QTY + 1  
                                                           WHERE WIP_ID = {data.wipID}";
                                // 執行原生 SQL
                                _context.Database.ExecuteSqlRaw(updateSql);
                            }
                        }
                        //}

                        // 判斷下一站為完工站
                        if (CheckNextStopCloseStation(data.flowRule, data.stationID, data.ruleStatus).Result.Success)
                        {
                            await CheckWipNoBarCodeAllClost(data.wipID);
                        }
                    }

                    // 燒入資料檔
                    Msg = await Table_BurnInfo(data);
                    if (!string.IsNullOrWhiteSpace(Msg))
                    {
                        throw new Exception($"BurnInfo_Error:{Msg}");
                    }

                    // 判斷是否有DB更新錯誤
                    if (string.IsNullOrWhiteSpace(Msg))
                    {
                        await tran.CommitAsync();
                    }
                    else
                    {
                        await tran.RollbackAsync();
                    }
                }

                catch (Exception ex)
                {
                    Msg = "過站新增系統錯誤:" + ex.Message;
                    await tran.RollbackAsync();
                }
            }

            return Msg;
        }

        /// <summary>
        /// BarcodeInfo-條碼資料檔
        /// </summary>
        /// <param name="data">model資料</param>
        /// <param name="id">BarCodeId 0=(修改) !=0(新增)</param>
        /// <returns></returns>
        private string Table_BarcodeInfo(BarCodeCheckDtoForDBData data, int id)
        {
            // 查看是否有資料
            var barcodeInfo = _context.BarcodeInfoes.Where(w => w.BarcodeID == data.barcodeID).FirstOrDefault();

            // 新增
            if (barcodeInfo == null)
            {
                barcodeInfo = new BarcodeInfo
                {
                    BarcodeID = id,
                    BarcodeNo = data.barcode,
                    StationID = data.stationID,
                    LocationID = -1,
                    WipID = data.wipID,
                    RuleStatus = data.ruleStatus,
                    StatusID = 1,
                    SysType = "S",
                    StatusNo = data.factoryUnit_UnitCode,
                    CreateUserID = data.userID
                };
            }
            // 更新
            else
            {
                barcodeInfo.StationID = data.stationID;
                barcodeInfo.RuleStatus = data.ruleStatus;
                barcodeInfo.StatusNo = data.factoryUnit_UnitCode;
                barcodeInfo.WipID = data.wipID;
                barcodeInfo.StatusID = 1;
                barcodeInfo.UpdateDate = DateTime.Now;
                if (!string.IsNullOrWhiteSpace(data.extNo))
                    barcodeInfo.ExtraBarcodeNo = data.extNo;
            }

            // 判斷該站別是否為最後一站
            if (CheckNextStopCloseStation(data.flowRule, data.stationID, data.ruleStatus).Result.Success)
            {
                barcodeInfo.StatusID = -1;
            }

            try
            {
                // 新增
                if (id != 0)
                {
                    _context.BarcodeInfoes.Add(barcodeInfo);
                }
                // 更新
                else
                {
                    _context.Entry(barcodeInfo).State = EntityState.Modified;
                    //設置容器空間某一個模型的某一個欄位 不提交到資料庫
                    _context.Entry<BarcodeInfo>(barcodeInfo).Property("CreateDate").IsModified = false;
                    _context.Entry<BarcodeInfo>(barcodeInfo).Property("CreateUserID").IsModified = false;
                }
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message + $" BarCodeID:{id} <br/>";
            }

            return "";
        }

        /// <summary>
        /// BarcodeStation-條碼過站資料檔
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string Table_BarcodeStation(BarCodeCheckDtoForDBData data)
        {
            // 新增 BarCodeStation
            BarcodeStation barcodeStation = new BarcodeStation
            {
                BarcodeID = data.barcodeID,
                WipID = data.wipID,
                StationID = data.stationID,
                RuleStatus = data.ruleStatus, //F 不良 
                InputDate = DateTime.Now,
                LineId = data.line,
                CreateUserID = data.userID,
                FlowRuleID = data.flowRule
            };

            try
            {
                _context.BarcodeStation.Add(barcodeStation);
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message;
            }
            return "";
        }

        /// <summary>
        /// BarcodeItem-組件资料
        /// </summary>
        /// <param name="data"></param>
        /// <param name="id">BarcodeItemID 陣列</param>
        /// <returns></returns>
        private string Table_BarcodeItem(BarCodeCheckDtoForDBData data, List<int> id)
        {
            var KeyPartsItem = data.inputItems.Where(w => !w.inputData.Contains("$")).ToList();
            var barcodeItem = new List<BarcodeItem>();
            // 新增 BarCodeStation
            for (int i = 0; i < KeyPartsItem.Count; i++)
            {
                var partNo = KeyPartsItem[i].inputData.Trim();
                var kpNo = KeyPartsItem[i].inputType.Trim();
                // MAC時,在確認是否重複
                if (kpNo.ToUpper().Contains("MAC"))
                {
                    if (SecondDuplicateCheckKP(data.wipNo, kpNo, data.unitNo, partNo))
                        return $"KP條碼有重複:{partNo}";
                }

                barcodeItem.Add(new BarcodeItem
                {
                    BarcodeItemID = id[i],
                    BarcodeID = data.barcodeID,
                    WipID = data.wipID,
                    StationID = data.stationID,
                    ItemNo = kpNo,
                    PartNo = partNo,
                    SysType = "S",
                    CreateUserID = data.userID,
                    CreateDate = DateTime.Now,
                    UpdateDate = DateTime.Now,
                    KpItemNo = KeyPartsItem[i].kpItemNo
                });
            }

            if (barcodeItem.Count != 0)
            {
                try
                {
                    _context.BarcodeItems.AddRange(barcodeItem);
                    _context.SaveChanges();
                }
                catch (Exception ex)
                {
                    return ex.InnerException.Message;
                }
            }

            return "";
        }

        /// <summary>
        /// BarCodeOutfit-治具資料
        /// </summary>
        /// <param name="data"></param>
        /// <param name="id">BarCodeOutfit ID List</param>
        /// <returns></returns>
        private string Table_BarcodeOutfit(BarCodeCheckDtoForDBData data, List<int> id)
        {
            var OutfitsItem = data.outfits;
            var barcodeOutfit = new List<BarcodeOutfit>();
            // 新增 BarCodeStation
            for (int i = 0; i < OutfitsItem.Count; i++)
            {
                barcodeOutfit.Add(new BarcodeOutfit
                {
                    BarcodeOutfitID = id[i],
                    BarcodeNo = data.barcode,
                    WipNo = data.wipNo,
                    OutfitNo = OutfitsItem[i].inputData,
                    StationID = data.stationID,
                    CreateUserID = data.userID,
                    CreateDate = DateTime.Now,
                    UpdateUserID = data.userID,
                    UpdateDate = DateTime.Now
                });
            }

            if (barcodeOutfit.Count != 0)
            {
                try
                {
                    _context.BarcodeOutfits.AddRange(barcodeOutfit);
                    _context.SaveChanges();
                }
                catch (Exception ex)
                {
                    return ex.InnerException.Message;
                }
            }
            return "";
        }

        /// <summary>
        /// OutfitInfo-設備資料檔 使用次數
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task<string> Table_OutfitInfo(BarCodeCheckDtoForDBData data)
        {
            OutfitInfoesController outfitInfoesController = new OutfitInfoesController(_context);
            var OutfitsItem = data.outfits.Where(w => !string.IsNullOrWhiteSpace(w.inputData)).ToList();
            foreach (var item in OutfitsItem)
            {
                #region SMT綁治具過站
                if (data.stations_Name.Contains("SMT"))
                {
                    // 查詢有效鋼板編號
                    var steelPlate = _context.SteelPlateInfos.Where(w => w.SteelPlateNo.Trim().ToUpper() == item.inputData.Trim().ToUpper() && w.Status == "1").FirstOrDefault();
                    if (steelPlate != null)
                    {
                        // 查詢鋼板紀錄沒有下線紀錄
                        var Measure = _context.SteelPlateMeasures.Where(w => w.SteelPlateID == steelPlate.SteelPlateID
                                                                             && w.OffUserID == null)
                                                                             .FirstOrDefault();
                        if (Measure != null)
                        {
                            // 確認第一次紀錄該筆工單號碼
                            if (!(Measure.WipNo ?? "").Contains(data.wipNo))
                            {
                                // 更新工單號碼到鋼板量測紀錄
                                if (string.IsNullOrWhiteSpace(Measure.WipNo))
                                    Measure.WipNo += data.wipNo;
                                else
                                    Measure.WipNo += "," + data.wipNo;
                                try
                                {
                                    _context.Entry(Measure).State = EntityState.Modified;
                                    await _context.SaveChangesAsync();
                                }
                                catch (Exception ex)
                                {
                                    return ex.InnerException.Message;
                                }

                                // 累加鋼板已使用次數
                                // 工單數量
                                var WipQty = _context.WipInfos.Where(w => w.WipID == data.wipID).FirstOrDefault().PlanQTY;
                                var Boards = _context.WipAtts.Where(w => w.WipNO == data.wipNo).FirstOrDefault().Boards;

                                steelPlate.BeUseTimes += WipQty / Boards;
                                steelPlate.TotalTimes += WipQty / Boards;

                                // 尚未通知且鋼板可使用次數不等於0
                                if (steelPlate.UsageFrequencyAlert == "N" && steelPlate.UsedTimes != 0)
                                {
                                    // 目前使用次數/可使用次數大於 95% 寄通知
                                    if ((steelPlate.BeUseTimes / steelPlate.UsedTimes) >= 0.95)
                                    {
                                        SteelPlateUse95Mail(steelPlate);
                                        steelPlate.UsageFrequencyAlert = "Y";
                                    }
                                }

                                try
                                {
                                    _context.Entry(steelPlate).State = EntityState.Modified;
                                    await _context.SaveChangesAsync();
                                }
                                catch (Exception ex)
                                {
                                    return ex.InnerException.Message;
                                }
                            }
                        }
                    }

                    // 查詢錫膏且出冰箱
                    var solderPaste = _context.SolderPasteInfos.Where(w => w.SolderPasteNo.ToUpper() == item.inputData.ToUpper()
                                                                         && (w.Status == "O" || w.Status == "U")).FirstOrDefault();
                    if (solderPaste != null)
                    {
                        // 出冰箱
                        if (solderPaste.Status == "O")
                        {
                            // 更新 錫膏狀態
                            string updateSql = $@" UPDATE JHAMES.SOLDER_PASTE_INFO SET STATUS ='U',
                                                       WIP_NO = '{data.wipNo}' ,
                                                       UPDATE_DATE = SYSDATE ,
                                                       UPDATE_USERID ='{data.userID}'  
                                                       WHERE SOLDER_PASTE_ID ={solderPaste.SolderPasteID}";
                            // 新增 錫膏紀錄
                            SolderPasteRecord solderPasteRecord = new SolderPasteRecord
                            {
                                SolderPasteID = solderPaste.SolderPasteID,
                                Status = "U",
                                CreateUserID = data.userID,
                                CreateDate = DateTime.Now
                            };

                            try
                            {
                                // 執行原生 SQL
                                _context.Database.ExecuteSqlRaw(updateSql);
                                _context.SolderPasteRecords.Add(solderPasteRecord);
                                _context.SaveChanges();
                            }
                            catch (Exception ex)
                            {
                                return ex.InnerException.Message;
                            }
                        }
                        // 已開封
                        else if (solderPaste.Status == "U")
                        {
                            // 確認第一次紀錄該筆工單號碼
                            if (!(solderPaste.WipNo ?? "").Contains(data.wipNo))
                            {
                                // 更新 錫膏工單
                                string updateSql = $@" UPDATE JHAMES.SOLDER_PASTE_INFO SET WIP_NO = WIP_NO || ',' || '{data.wipNo}',
                                                       UPDATE_DATE = SYSDATE ,
                                                       UPDATE_USERID ='{data.userID}'  
                                                       WHERE SOLDER_PASTE_ID ={solderPaste.SolderPasteID}";
                                try
                                {
                                    // 執行原生 SQL
                                    _context.Database.ExecuteSqlRaw(updateSql);
                                    _context.SaveChanges();
                                }
                                catch (Exception ex)
                                {
                                    return ex.InnerException.Message;
                                }
                            }
                        }
                    }
                }
                #endregion

                #region 一般 治具過站
                else
                {
                    var outfitInfo = _context.OutfitInfoes.Where(w => w.OutfitNo == item.inputData.ToUpper()).FirstOrDefault();
                    if (outfitInfo != null)
                    {
                        outfitInfo.UseTimes += 1;
                        outfitInfo.TotalTimes += 1;
                        outfitInfo.UpdateDate = DateTime.Now;

                        try
                        {
                            _context.Entry(outfitInfo).State = EntityState.Modified;
                            await _context.SaveChangesAsync();
                        }
                        catch (Exception ex)
                        {
                            return ex.InnerException.Message;
                        }
                        WipAlarmsController wipAlarmsController = new WipAlarmsController(_context);
                        var wipAlarms = await wipAlarmsController.GetWipAlarmByOutfit(data.wipNo, item.inputData.Trim().ToUpper());
                        // 判斷確認治具編號是否已到預警提醒
                        if (outfitInfoesController.GetOutfitInfoByAlertTimes(item.inputData.Trim().ToUpper()).Result.Value == "Y")
                        {
                            if (!wipAlarms.Value.Where(w => w.AlarmTypeID == (int)EnumWipAlarm.EnumTypeId.OutfitAlert).Any())
                            {
                                string MailGroup = "OUTFIT_ALARM";
                                string Subject = $"[AMES系統通知] 治具編號:{item.inputData.Trim().ToUpper()},預警提前通知";
                                string Body = "";

                                await new MailController(_context, _config).PostMail(Subject, Body, MailGroup, "", false);

                                WipAlarm wipAlarm = new WipAlarm();
                                wipAlarm.AlarmTypeID = (int)EnumWipAlarm.EnumTypeId.OutfitAlert;
                                wipAlarm.WipNO = data.wipNo;
                                wipAlarm.AlarmParam = item.inputData.ToUpper();
                                wipAlarm.AlarmValue = "1";
                                wipAlarm.AlarmDesc = Subject;
                                wipAlarm.AlarmDateTime = DateTime.Now;

                                await wipAlarmsController.PostWipAlarm(wipAlarm);
                            }
                        }
                    }
                }
                #endregion
                //// 確認治具編號使用次數已經超過預計次數
                //if (outfitInfoesController.GetOutfitInfoByOverUseTimes("").Result.Value == "Y")
                //{

                //}
            }
            return "";
        }

        /// <summary>
        /// BurnInfo-燒入資料檔
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task<string> Table_BurnInfo(BarCodeCheckDtoForDBData data)
        {
            // 判斷作業站是否為燒機站 Station_Type == B 
            if (data.stations_TypeNo == "B")
            {
                // 判斷是否有燒機時間
                WipBoardController wipBoardController = new WipBoardController(_context);
                var wipBoardTime = await wipBoardController.GetWipBoardToBITime(data.wipNo);
                WipSystemController wipSystemController = new WipSystemController(_context);
                var wipSystemTime = await wipSystemController.GetWipSystemToBITime(data.wipNo);
                decimal PlanHour = 0;
                if (wipBoardTime.Value > 0)
                    PlanHour = (decimal)wipBoardTime.Value;
                else
                    PlanHour = (decimal)wipSystemTime.Value;

                // 確認有燒機資訊
                var burnInfos = await _context.BurnInfos.Where(w => w.BarcodeID == data.barcodeID &&
                                                                    w.FinishTime == null)
                                                        .FirstOrDefaultAsync();
                try
                {
                    // 新增
                    if (burnInfos == null)
                    {
                        Helper helper = new Helper(_context);
                        // 新增 BarCodeStation
                        var burnInfo = new BurnInfo
                        {
                            BurnID = await helper.GetIDKey("BURN_ID"),
                            BarcodeID = data.barcodeID,
                            WipNo = data.wipNo,
                            BurnPlanHour = PlanHour,
                            StartTime = DateTime.Now,
                            ScheduleFinishTime = DateTime.Now.AddMinutes((double)PlanHour * 60),
                            InUserID = data.userID,
                            Status = 0,
                            CreateUserID = data.userID,
                            UpdateUserID = data.userID
                        };
                        _context.BurnInfos.Add(burnInfo);
                    }
                    else
                    {
                        burnInfos.Status = 1;
                        burnInfos.FinishTime = DateTime.Now;
                        burnInfos.OutUserID = data.userID;
                        burnInfos.UpdateDate = DateTime.Now;
                        burnInfos.UpdateUserID = data.userID;

                        _context.Entry(burnInfos).State = EntityState.Modified;
                        //設置容器空間某一個模型的某一個欄位 不提交到資料庫
                        _context.Entry<BurnInfo>(burnInfos).Property("CreateDate").IsModified = false;
                        _context.Entry<BurnInfo>(burnInfos).Property("CreateUserID").IsModified = false;
                    }
                    await _context.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    return ex.InnerException.Message;
                }
            }
            return "";
        }

        /// <summary>
        /// NgInfo-測試不良基本資料檔
        /// </summary>
        /// <param name="data"></param>
        /// <param name="ngId">Db ID</param>
        /// <param name="componentId">Db ID</param>
        /// <returns></returns>
        private string Table_NgInfo(BarCodeCheckDtoForDBData data, int ngId, List<int> componentId)
        {
            var NgItem = data.inputItems.Where(w => w.inputData.Contains("$")).ToList();

            try
            {
                // 新增 NgInfo
                if (NgItem.Count != 0)
                {
                    NgInfo ngInfo = new NgInfo
                    {
                        NgID = ngId,
                        TypeNo = data.stations_TestType,
                        OperatorID = 0,
                        FixtureNo = "NA",
                        BarcodeID = data.barcodeID,
                        ReasonNo = NgItem[0].inputData.Replace("$", "").Trim().ToUpper(),
                        ProgramNo = "N/A",
                        MachineNo = "N/A",
                        StationId = data.stationID,
                        WipId = data.wipID,
                        CreateUserID = data.userID,
                        UpdateUserID = data.userID
                    };
                    _context.NgInfos.Add(ngInfo);

                    var ngComponent = new List<NgComponent>();
                    for (int i = 0; i < NgItem.Count; i++)
                    {
                        ngComponent.Add(new NgComponent
                        {
                            NgID = ngId,
                            ComponentID = componentId[i],
                            LocationNo = string.IsNullOrWhiteSpace(NgItem[i].oldInputData) ? "N/A" : NgItem[i].oldInputData,
                            NgNo = NgItem[i].inputData.Replace("$", "").Trim().ToUpper(),
                            CreateUserID = data.userID,
                            UpdateUserID = data.userID
                        });


                        // 累計預警
                        WipAlarmsController wipAlarmsController = new WipAlarmsController(_context);
                        wipAlarmsController.PostWipAlarm4ErrorCode(data.wipNo, NgItem[i].inputData.Replace("$", "")).Wait();
                    }
                    _context.NgComponents.AddRange(ngComponent);
                    _context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message;
            }
            return "";
        }

        /// <summary>
        /// BarcodeWip-檔案用途    條碼工單資料檔
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string Table_BarcodeWip(BarCodeCheckDtoForDBData data)
        {
            var barcodeWip = _context.BarcodeWips.Where(w => w.BarcodeID == data.barcodeID &&
                                                             w.WipID == data.wipID).FirstOrDefault();
            try
            {
                // 新增
                if (barcodeWip == null)
                {
                    barcodeWip = new BarcodeWip
                    {
                        BarcodeID = data.barcodeID,
                        WipID = data.wipID,
                        CreateUserID = data.userID
                    };
                    _context.BarcodeWips.Add(barcodeWip);
                }
                // 更新
                else
                {
                    barcodeWip.UpdateDate = DateTime.Now;
                    _context.Attach(barcodeWip);
                    _context.Entry(barcodeWip).Property(p => p.UpdateDate).IsModified = true;
                }
                _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message + "<br/>";
            }
            return "";
        }

        /// <summary>
        /// WipStation
        /// </summary>
        /// <returns></returns>
        private string Table_WipStation(BarCodeCheckDtoForDBData data)
        {
            var BarcodeStation = _context.BarcodeStation.Where(w => w.BarcodeID == data.barcodeID &&
                                                                            w.WipID == data.wipID && w.StationID == data.stationID &&
                                                                            w.FlowRuleID == data.flowRule).Any();
            var today = DateTime.Now.ToString("yyyy/MM/dd");
            // 判斷是否有資料
            var wipStations = _context.WipStations.Where(w => w.WipID == data.wipID && w.StationID == data.stationID &&
                                                              w.RuleStatus == data.ruleStatus).ToList();
            wipStations = wipStations.Where(w => w.CreateDate.ToString("yyyy/MM/dd") == today).ToList();
            try
            {
                // 新增
                if (wipStations.Count() == 0)
                {
                    var firstCnt = 1;
                    // 有過站資料不能第一次
                    if (BarcodeStation)
                        firstCnt = 0;

                    _context.WipStations.Add(new WipStation
                    {
                        WipID = data.wipID,
                        RuleStatus = data.ruleStatus,
                        StationID = data.stationID,
                        FirstCnt = firstCnt,
                        PassCnt = 1,
                        CreateUserID = data.userID
                    });
                    _context.SaveChangesAsync();
                }
                // 更新
                else
                {

                    // 有資料加1 後續判斷第一次過站
                    string updateSql = @" UPDATE JHAMES.WIP_STATION SET PASS_CNT = PASS_CNT + 1 , 
                                          UPDATE_DATE = SYSDATE";
                    if (!BarcodeStation)
                    {
                        updateSql += " , FIRST_CNT = FIRST_CNT + 1 ";
                    }
                    updateSql += $@" WHERE WIP_ID = '{data.wipID}' 
                                     AND STATION_ID = '{data.stationID}' 
                                     AND RULE_STATUS = '{data.ruleStatus}'
                                     AND TO_CHAR(CREATE_DATE , 'YYYY/MM/DD') = '{today}' ";
                    // 執行原生 SQL
                    _context.Database.ExecuteSqlRaw(updateSql);
                }
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message + "<br/>";
            }
            return "";
        }

        /// <summary>
        /// WipClass-各班別數量資料檔
        /// </summary>
        /// <returns></returns>
        private string Table_WipClass(BarCodeCheckDtoForDBData data)
        {
            var BarcodeStation = _context.BarcodeStation.Where(w => w.BarcodeID == data.barcodeID &&
                                                                                          w.WipID == data.wipID && w.StationID == data.stationID &&
                                                                                          w.FlowRuleID == data.flowRule).Any();
            var today = DateTime.Now.ToString("yyyy/MM/dd");
            // 取ClassID 
            int ClassID = -1;
            var ClassInfo = _context.ClassInfoes.Where(w => w.UnitNo == data.unitNo).ToList();

            ClassInfo = ClassInfo.Where(w => DateTime.Parse(today + " " + w.BeginTime) <= DateTime.Now &&
                                             DateTime.Now <= DateTime.Parse(today + " " + w.EndTime)).ToList();
            if (ClassInfo.Count() != 0)
            {
                ClassID = ClassInfo.FirstOrDefault().ClassID;
            }

            // 判斷是否有資料
            var wipClasses = _context.WipClass.Where(w => w.WipID == data.wipID && w.StationID == data.stationID &&
                                                              w.RuleStatus == data.ruleStatus && w.ClassID == ClassID).ToList();

            wipClasses = wipClasses.Where(w => w.CreateDate.ToString("yyyy/MM/dd") == today).ToList();

            try
            {
                // 新增
                if (wipClasses.Count() == 0)
                {
                    var firstCnt = 1;
                    // 有過站資料不能第一次
                    if (BarcodeStation)
                        firstCnt = 0;
                    _context.WipClass.Add(new WipClass
                    {
                        WipID = data.wipID,
                        RuleStatus = data.ruleStatus,
                        StationID = data.stationID,
                        ClassID = ClassID,
                        FirstCnt = firstCnt,
                        PassCnt = 1,
                        CreateUserID = data.userID
                    });
                    _context.SaveChanges();
                }
                // 更新
                else
                {
                    // 有資料加1 後續判斷第一次過站
                    string updateSql = @" UPDATE JHAMES.WIP_CLASS SET PASS_CNT = PASS_CNT + 1 , 
                                          UPDATE_DATE = SYSDATE";
                    if (!BarcodeStation)
                    {
                        updateSql += " , FIRST_CNT = FIRST_CNT + 1 ";
                    }
                    updateSql += $@" WHERE WIP_ID = '{data.wipID}' 
                                     AND STATION_ID = '{data.stationID}' 
                                     AND RULE_STATUS = '{data.ruleStatus}'
                                     AND CLASS_ID = {ClassID}
                                     AND TO_CHAR(CREATE_DATE , 'YYYY/MM/DD') = '{today}' ";
                    // 執行原生 SQL
                    _context.Database.ExecuteSqlRaw(updateSql);
                }
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message + "<br/>";
            }
            return "";
        }

        /// <summary>
        /// WipTime-工單各站數量資料檔 – By TIME
        /// </summary>
        /// <returns></returns>
        private string Table_WipTime(BarCodeCheckDtoForDBData data)
        {
            // 有資料加1 後續判斷第一次過站
            var BarcodeStation = _context.BarcodeStation.Where(w => w.BarcodeID == data.barcodeID &&
                                                                             w.WipID == data.wipID && w.StationID == data.stationID &&
                                                                             w.FlowRuleID == data.flowRule).Any();

            var today = DateTime.Now.ToString("yyyy/MM/dd");
            // 取SegmentID 
            int SegmentID = -1;
            var timeSegment = _context.TimeSegments.ToList();

            timeSegment = timeSegment.Where(w => DateTime.Parse(today + " " + w.StartTime) <= DateTime.Now &&
                                                 DateTime.Now <= DateTime.Parse(today + " " + w.EndTime)).ToList();
            if (timeSegment.Count() != 0)
            {
                SegmentID = timeSegment.FirstOrDefault().SegmentID;
            }

            // 判斷是否有資料
            var wipTimes = _context.WipTimes.Where(w => w.WipID == data.wipID && w.StationID == data.stationID &&
                                                             w.RuleStatus == data.ruleStatus && w.SegmentID == SegmentID).ToList();


            wipTimes = wipTimes.Where(w => w.CreateDate.ToString("yyyy/MM/dd") == today).ToList();
            try
            {
                // 新增
                if (wipTimes.Count() == 0)
                {
                    var firstCnt = 1;
                    // 有過站資料不能第一次
                    if (BarcodeStation)
                        firstCnt = 0;

                    _context.WipTimes.Add(new WipTime
                    {
                        WipID = data.wipID,
                        RuleStatus = data.ruleStatus,
                        StationID = data.stationID,
                        SegmentID = SegmentID,
                        FirstCnt = firstCnt,
                        PassCnt = 1,
                        CreateUserID = data.userID
                    });
                    _context.SaveChanges();
                }
                // 更新
                else
                {
                    // 有資料加1 後續判斷第一次過站
                    string updateSql = @" UPDATE JHAMES.WIP_TIME SET PASS_CNT = PASS_CNT + 1 , 
                                          UPDATE_DATE = SYSDATE";
                    if (!BarcodeStation)
                    {
                        updateSql += " , FIRST_CNT = FIRST_CNT + 1 ";
                    }
                    updateSql += $@" WHERE WIP_ID = '{data.wipID}' 
                                     AND STATION_ID = '{data.stationID}' 
                                     AND RULE_STATUS = '{data.ruleStatus}'
                                     AND SEGMENT_ID = {SegmentID}
                                     AND TO_CHAR(CREATE_DATE , 'YYYY/MM/DD') = '{today}' ";
                    // 執行原生 SQL
                    _context.Database.ExecuteSqlRaw(updateSql);
                }

            }
            catch (Exception ex)
            {
                return ex.InnerException.Message + "<br/>";
            }
            return "";
        }

        /// <summary>
        /// WipKp-工單keyParts 長度更新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string Table_WipKps(List<WipKp> data, int userId)
        {
            try
            {
                // 查看是否有資料
                foreach (var item in data)
                {
                    var wipKp = _context.WipKps.Where(w => w.WipKpID == item.WipKpID).FirstOrDefault();
                    if (wipKp != null)
                    {
                        wipKp.Length = item.Length;
                        wipKp.UpdateUserID = userId;
                        wipKp.UpdateDate = DateTime.Now;
                        _context.Entry(wipKp).State = EntityState.Modified;
                        //設置容器空間某一個模型的某一個欄位 不提交到資料庫
                        _context.Entry<WipKp>(wipKp).Property("CreateDate").IsModified = false;
                        _context.Entry<WipKp>(wipKp).Property("CreateUserID").IsModified = false;
                        _context.SaveChangesAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                return ex.InnerException.Message;
            }
            return "";
        }

        #endregion

        #region 判斷過站完成新增or更新 By FQC
        /// <summary>
        /// 判斷過站完成新增or更新 Table
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task<string> CU_TablesByFQC(List<BarCodeCheckDtoForDBData> data)
        {
            using (var tran = _context.Database.BeginTransaction())
            {
                try
                {
                    // T-SQL 查詢資料
                    int wipId = data.FirstOrDefault().wipID;
                    int stationId = data.FirstOrDefault().stationID;
                    int flowRule = data.FirstOrDefault().flowRule;
                    int createUserId = data.FirstOrDefault().userID;
                    int dataQty = data.Count();
                    string unitNo = data.FirstOrDefault().unitNo;
                    string ruleStatus = "P";
                    DynamicParameters p = new DynamicParameters();

                    #region 條碼主檔
                    var upBarCodeInfo = @" UPDATE JHAMES.BARCODE_INFO SET 
                                           STATION_ID =:stationID ,
                                           RULE_STATUS = 'P' ,
                                           LOCATION_ID = '-1' ,
                                           UPDATE_DATE = SYSDATE
                                           WHERE BARCODE_ID = :barcodeID 
                                           AND WIP_ID = :wipID ";
                    _context.Database.DapperExecute(upBarCodeInfo, data);

                    // 判斷該站別是否為最後一站
                    if (CheckNextStopCloseStation(flowRule, stationId, ruleStatus).Result.Success)
                    {
                        upBarCodeInfo = @" UPDATE JHAMES.BARCODE_INFO SET 
                                           STATUS_ID ='-1'  
                                           WHERE BARCODE_ID = :barcodeID 
                                           AND WIP_ID = :wipID ";
                        _context.Database.DapperExecute(upBarCodeInfo, data);
                    }

                    #endregion

                    #region 條碼紀錄

                    var upBarCodeWip = @" UPDATE JHAMES.BARCODE_WIP
                                          SET UPDATE_DATE = SYSDATE
                                          WHERE BARCODE_ID = :barcodeID 
                                          AND WIP_ID = :wipID ";
                    _context.Database.DapperExecute(upBarCodeWip, data);

                    #endregion

                    #region 條碼過站資料檔

                    var inBarCodeStation = @" BEGIN INSERT INTO JHAMES.BARCODE_STATION
                                             (
                                             BARCODE_ID,
                                             WIP_ID,
                                             FLOW_RULE_ID,
                                             STATION_ID,
                                             RULE_STATUS,
                                             INPUT_DATE,
                                             SYSTYPE,
                                             LINE_ID,
                                             STATION_FLAG,
                                             STATION_TIMES,
                                             CREATE_USERID,
                                             CREATE_DATE
                                            ) VALUES (
                                             :barcodeID,
                                             :wipID,
                                             :flowRule,
                                             :stationID,
                                             'P',
                                             SYSDATE,
                                             'S',
                                             :line,
                                             '1',
                                             '1',
                                             :userID,
                                             SYSDATE
                                            );
                                            EXCEPTION
                                            WHEN DUP_VAL_ON_INDEX THEN
                                            NULL;
                                            END;  ";
                    _context.Database.DapperExecute(inBarCodeStation, data);

                    #endregion

                    #region 工單各站數量資料檔

                    var queryWipStation = @"SELECT * FROM JHAMES.WIP_STATION WHERE WIP_ID = :WipId
                                            AND STATION_ID = :StationId
                                            AND RULE_STATUS ='P'
                                            AND TRUNC(CREATE_DATE) = TRUNC(SYSDATE) ";

                    p = new DynamicParameters();
                    p.Add("WipId", wipId);
                    p.Add("StationId", stationId);
                    var reautWipStation = _context.Database.DapperQuery<dynamic>(queryWipStation, p);

                    // 新增
                    if (!reautWipStation.Any())
                    {
                        var insertSql = @"  BEGIN INSERT INTO JHAMES.WIP_STATION
                                                 (
                                                 WIP_ID,
                                                 STATION_ID,
                                                 RULE_STATUS,
                                                 FIRST_CNT,
                                                 PASS_CNT,
                                                 CREATE_USERID,
                                                 CREATE_DATE,
                                                 UPDATE_DATE
                                                ) VALUES (
                                                 :WipId,
                                                 :StationId,
                                                 'P',
                                                 :FirstCnt,
                                                 :PassCnt,
                                                 :UserID,
                                                 SYSDATE,
                                                 SYSDATE
                                                );
                                                EXCEPTION
                                                WHEN DUP_VAL_ON_INDEX THEN
                                                NULL;
                                                END; ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("UserID", createUserId);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(insertSql, p);
                    }
                    // 更新
                    else
                    {
                        // 有資料加1 後續判斷第一次過站
                        var updateSql = @"  UPDATE JHAMES.WIP_STATION SET PASS_CNT = PASS_CNT + :PassCnt , 
                                                UPDATE_DATE = SYSDATE , 
                                                FIRST_CNT = FIRST_CNT + :FirstCnt 
                                                WHERE WIP_ID = :WipId 
                                                AND STATION_ID = :StationId
                                                AND RULE_STATUS = 'P'
                                                AND TRUNC(CREATE_DATE) = TRUNC(SYSDATE) ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(updateSql, p);
                    }

                    #endregion

                    #region 各班別數量資料檔

                    // 取ClassID 
                    int ClassID = -1;
                    var queryClassInfo = @" SELECT * FROM JHAMES.CLASS_INFO 
                                            WHERE UNIT_NO = :UnitNo
                                            AND SYSTIMESTAMP BETWEEN
                                                TO_TIMESTAMP(TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' ' || BEGIN_TIME, 'YYYY-MM-DD HH24:MI')
                                            AND TO_TIMESTAMP(TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' ' || END_TIME, 'YYYY-MM-DD HH24:MI')";

                    p = new DynamicParameters();
                    p.Add("UnitNo", unitNo);
                    var reautClassInfo = _context.Database.DapperQuery<dynamic>(queryClassInfo, p);

                    if (reautClassInfo.Any())
                    {
                        ClassID = (int)reautClassInfo.FirstOrDefault().CLASS_ID;
                    }

                    // 判斷是否有資料
                    var queryWipClass = @"  SELECT * FROM JHAMES.WIP_CLASS WHERE WIP_ID = :WipId
                                            AND STATION_ID = :StationId
                                            AND RULE_STATUS ='P'
                                            AND CLASS_ID = :ClassId
                                            AND TRUNC(CREATE_DATE) = TRUNC(SYSDATE) ";

                    p = new DynamicParameters();
                    p.Add("WipId", wipId);
                    p.Add("StationId", stationId);
                    p.Add("ClassId", ClassID);
                    var reautWipClass = _context.Database.DapperQuery<dynamic>(queryWipClass, p);

                    // 新增
                    if (!reautWipClass.Any())
                    {
                        var insertSql = @"  BEGIN INSERT INTO JHAMES.WIP_CLASS
                                                 (
                                                 WIP_ID,
                                                 STATION_ID,
                                                 RULE_STATUS,
                                                 CLASS_ID,
                                                 FIRST_CNT,
                                                 PASS_CNT,
                                                 CREATE_USERID,
                                                 CREATE_DATE,
                                                 UPDATE_DATE
                                                ) VALUES (
                                                 :WipId,
                                                 :StationId,
                                                 'P',
                                                 :ClassId,
                                                 :FirstCnt,
                                                 :PassCnt,
                                                 :UserID,
                                                 SYSDATE,
                                                 SYSDATE
                                                );
                                                EXCEPTION
                                                WHEN DUP_VAL_ON_INDEX THEN
                                                NULL;
                                                END; ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("UserID", createUserId);
                        p.Add("ClassId", ClassID);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(insertSql, p);
                    }
                    // 更新
                    else
                    {
                        // 有資料加1 後續判斷第一次過站
                        string updateSql = @" UPDATE JHAMES.WIP_CLASS SET PASS_CNT = PASS_CNT + :PassCnt , 
                                                  UPDATE_DATE = SYSDATE ,
                                                  FIRST_CNT = FIRST_CNT + :FirstCnt
                                                  WHERE WIP_ID = :WipId
                                                  AND STATION_ID = :StationId
                                                  AND RULE_STATUS = 'P'
                                                  AND CLASS_ID = :ClassId
                                                  AND TRUNC(CREATE_DATE) = TRUNC(SYSDATE) ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("ClassId", ClassID);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(updateSql, p);
                    }

                    #endregion

                    #region 工單各站數量資料檔 – By TIME

                    // 取SegmentID 
                    int SegmentID = -1;
                    var queryTimeSegment = @" SELECT * FROM JHAMES.TIME_SEGMENT
                                                WHERE SYSTIMESTAMP BETWEEN
                                                    TO_TIMESTAMP(TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' ' || START_TIME, 'YYYY-MM-DD HH24:MI')
                                                AND TO_TIMESTAMP(TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' ' || END_TIME, 'YYYY-MM-DD HH24:MI')";

                    p = new DynamicParameters();
                    var reautTimeSegment = _context.Database.DapperQuery<dynamic>(queryTimeSegment, p);

                    if (reautTimeSegment.Any())
                    {
                        SegmentID = (int)reautTimeSegment.FirstOrDefault().SEGMENT_ID;
                    }

                    // 判斷是否有資料
                    var queryWipTime = @"  SELECT * FROM JHAMES.WIP_TIME 
                                                WHERE WIP_ID = :WipId
                                                AND STATION_ID = :StationId
                                                AND RULE_STATUS ='P'
                                                AND SEGMENT_ID = :SegmentID ";
                    p = new DynamicParameters();
                    p.Add("WipId", wipId);
                    p.Add("StationId", stationId);
                    p.Add("SegmentID", SegmentID);
                    var reautWipTime = _context.Database.DapperQuery<dynamic>(queryWipTime, p);

                    // 新增
                    if (!reautWipTime.Any())
                    {
                        var insertSql = @"  BEGIN INSERT INTO JHAMES.WIP_TIME
                                                     (
                                                     WIP_ID,
                                                     STATION_ID,
                                                     RULE_STATUS,
                                                     SEGMENT_ID,
                                                     FIRST_CNT,
                                                     PASS_CNT,
                                                     CREATE_USERID,
                                                     CREATE_DATE,
                                                     UPDATE_DATE
                                                    ) VALUES (
                                                     :WipId,
                                                     :StationId,
                                                     'P',
                                                     :SegmentID,
                                                     :FirstCnt,
                                                     :PassCnt,
                                                     :UserID,
                                                     SYSDATE,
                                                     SYSDATE
                                                    );
                                                    EXCEPTION
                                                    WHEN DUP_VAL_ON_INDEX THEN
                                                    NULL;
                                                    END; ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("UserID", createUserId);
                        p.Add("SegmentID", SegmentID);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(insertSql, p);
                    }
                    // 更新
                    else
                    {
                        // 有資料加1 後續判斷第一次過站
                        string updateSql = @" UPDATE JHAMES.WIP_TIME SET PASS_CNT = PASS_CNT + :PassCnt , 
                                                  UPDATE_DATE = SYSDATE ,
                                                  FIRST_CNT = FIRST_CNT + :FirstCnt
                                                  WHERE WIP_ID = :WipId
                                                  AND STATION_ID = :StationId
                                                  AND RULE_STATUS = 'P'
                                                  AND SEGMENT_ID = :SegmentID
                                                  AND TRUNC(CREATE_DATE) = TRUNC(SYSDATE) ";
                        p = new DynamicParameters();
                        p.Add("WipId", wipId);
                        p.Add("StationId", stationId);
                        p.Add("SegmentID", SegmentID);
                        p.Add("FirstCnt", dataQty);
                        p.Add("PassCnt", dataQty);
                        _context.Database.DapperExecute(updateSql, p);
                    }

                    #endregion

                    // 判斷下一站為完工站
                    if (CheckNextStopCloseStation(flowRule, stationId, "P").Result.Success)
                    {
                        await CheckWipNoBarCodeAllClost(wipId);
                    }

                    await tran.CommitAsync();
                    return "";
                }
                catch (Exception ex)
                {
                    await tran.RollbackAsync();
                    return "FQC新增系統錯誤:" + ex.Message;
                }
            }
        }
        #endregion

        /// <summary>
        /// 判斷工單狀態
        /// </summary>
        /// <param name="wipno">工單號碼</param>
        /// <param name="unitno">生產單位</param>
        /// <param name="line">線別</param>
        /// <param name="flowrule">流程</param>
        /// <param name="stationID">作業站ID</param>
        /// <returns></returns>
        [HttpGet("CheckWipNoSation")]
        public IActionResult GetCheckWipNoSation(string wipno, string unitno, int line, int flowrule, int stationID)
        {
            var result = CheckWipNoSationAsync(wipNo: wipno, unitNo: unitno, flowRuleID: flowrule, line: line, stationID: stationID);
            return Ok(result.Result);
        }

        /// <summary>
        /// 內部序號查詢工單號碼
        /// </summary>
        /// <param name="barcode">內部序號</param>
        /// <returns>Success:true or false</returns>
        [HttpGet("BarCodeFromWip")]
        public async Task<IResultModel> CheckBarCodeFromWip(string barcode)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            if (barcode.Length <= 4)
            {
                resultModel.Msg = "內部序號小於4個字數";
                return resultModel;
            }

            // 內部序號扣除流水號 查詢
            var SerialNumber = await GetWipNoSerialNumber("");
            IQueryable<WipBarcode> q = _context.WipBarcodes.Where(w => w.StartNO.Substring(0, (barcode.Length - SerialNumber)) == (barcode.Substring(0, (barcode.Length - SerialNumber))));
            if (!q.Any())
            {
                resultModel.Msg = "找不到內部序號【" + barcode + "】 對應相關工單號碼";
                return resultModel;
            }
            else
            {
                try
                {
                    var No = int.Parse(barcode.Substring(barcode.Length - SerialNumber, SerialNumber));
                    foreach (var item in q)
                    {
                        int StartNo = int.Parse(item.StartNO.Substring(item.StartNO.Length - SerialNumber, SerialNumber));
                        int EndNo = int.Parse(item.EndNO.Substring(item.EndNO.Length - SerialNumber, SerialNumber));
                        if (StartNo <= No && No <= EndNo)
                        {
                            resultModel.Success = true;
                            resultModel.Msg = q.Select(s => s.WipNO).FirstOrDefault();
                            return resultModel;
                        }
                    }
                    resultModel.Msg = "工單號碼【" + q.Select(s => s.WipNO).FirstOrDefault() + "】 找不到範圍內的內部序號";
                }
                catch (Exception ex)
                {
                    resultModel.Msg = ex.Message;
                }
            }

            return resultModel;
        }

        /// <summary>
        /// 查詢序號是否有在該工單 條碼區間內
        /// </summary>
        /// <param name="barcode">內部序號</param>
        /// <param name="wipNo">工單號碼</param>
        //[HttpGet("CheckBarCodeByWipNo")]
        private async Task<ResultModel<string>> CheckBarCodeByWipNo(string barcode, string wipNo)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            if (barcode.Length <= 4)
            {
                resultModel.Msg = "內部序號小於4個字數";
                return resultModel;
            }

            // 內部序號扣除流水號 查詢
            var q = await _context.WipBarcodes.Where(w => w.WipNO == wipNo).ToListAsync();
            if (!q.Any())
            {
                resultModel.Msg = "找不到工單號碼【" + wipNo + "】 有設定條碼區間";
                return resultModel;
            }
            else
            {
                try
                {
                    // 刷入資料 = 條碼起始 或 條碼結束 都符合條碼區間
                    if (q.Where(w => w.StartNO == barcode || w.EndNO == barcode).Any())
                    {
                        resultModel.Success = true;
                        return resultModel;
                    }

                    // 取工單號碼最大工單數量
                    int snLen = await GetWipNoSerialNumber(wipNo);
                    // 93200036400001 9320003640001
                    var No = int.Parse(barcode.Substring(barcode.Length - snLen, snLen));
                    foreach (var item in q.Where(w => w.StartNO.Substring(0, barcode.Length - snLen) == barcode.Substring(0, barcode.Length - snLen)
                                                        && w.StartNO.Length == barcode.Length))
                    {
                        int StartNo = int.Parse(item.StartNO.Substring(item.StartNO.Length - snLen, snLen));
                        int EndNo = int.Parse(item.EndNO.Substring(item.EndNO.Length - snLen, snLen));
                        if (StartNo <= No && No <= EndNo)
                        {
                            resultModel.Success = true;
                            return resultModel;
                        }
                    }
                    resultModel.Msg = "工單號碼【" + wipNo + "】 找不到範圍內的內部序號【" + barcode + "】";
                }
                catch (Exception ex)
                {
                    resultModel.Msg = ex.Message;
                }
            }
            return resultModel;
        }

        /// <summary>
        /// 查詢序號是否有在該工單 條碼區間內(過站使用)
        /// </summary>
        /// <param name="barcode">內部序號</param>
        /// <param name="wipNo">工單號碼</param>
        [HttpGet("CheckBarCodeByWipNo")]
        public async Task<ResultModel<string>> CheckBarCodeByWipNo_New(string barcode, string wipNo)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            if (barcode.Length <= 4)
            {
                resultModel.Msg = "內部序號小於4個字數";
                return resultModel;
            }

            // 內部序號扣除流水號 查詢
            var q = await _context.WipBarcodes.Where(w => w.WipNO == wipNo).ToListAsync();
            if (!q.Any())
            {
                resultModel.Msg = "找不到工單號碼【" + wipNo + "】 有設定條碼區間";
                return resultModel;
            }
            else
            {
                try
                {
                    // 刷入資料 = 條碼起始 或 條碼結束 都符合條碼區間
                    if (q.Where(w => w.StartNO == barcode || w.EndNO == barcode).Any())
                    {
                        resultModel.Success = true;
                        return resultModel;
                    }

                    var query = @$" SELECT * FROM JHAMES.WIP_BARCODE
                                    WHERE WIP_NO =:WipNo -- 工單號碼
                                    AND :BarCode BETWEEN START_NO AND END_NO -- 判斷區間
                                    AND LENGTH(:BarCode) = LENGTH(START_NO) -- 判斷長度 ";

                    DynamicParameters p = new DynamicParameters();
                    p.Add("WipNo", wipNo);
                    p.Add("BarCode", barcode);

                    var q1 = await _context.Database.DapperQueryAsync<dynamic>(query, p);
                    if (q1.Any())
                    {
                        resultModel.Success = true;
                        return resultModel;
                    }
                    else
                        resultModel.Msg = $"工單號碼【{wipNo}】 找不到範圍內的內部序號【{barcode}】";
                }
                catch (Exception ex)
                {
                    resultModel.Msg = ex.Message;
                }
            }

            return resultModel;
        }

        /// <summary>
        /// 內部序號是否鎖定
        /// </summary>
        /// <param name="barCode">內部序號ID</param>
        /// <param name="barCodeNo">內部序號</param>
        /// <returns>Success:true or false</returns>
        [HttpGet("BarCodeLock")]
        public async Task<ResultModel<string>> CheckBarCodeLockAsync(int barCode, string barCodeNo)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            if (barCodeNo.Length <= 4)
            {
                resultModel.Msg = "內部序號小於4個字數";
                return resultModel;
            }

            // 第一次投入 沒有資料 不用判斷
            if (barCode == 0)
            {
                resultModel.Success = true;
                return resultModel;
            }

            var BarCodeLock = _context.BarcodeLocks.Where(w => w.BarcodeID == barCode && w.LockStatus == 0).FirstOrDefaultAsync();
            if (await BarCodeLock != null)
            {
                resultModel.Msg = $"內部序號【{barCodeNo}】在當前站別被鎖定,不可過站";
                return resultModel;
            }

            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 內部序號是否報廢
        /// </summary>
        /// <param name="barCode">內部序號ID</param>
        /// <param name="barCodeNo">內部序號</param>
        /// <returns>Success:true or false</returns>
        [HttpGet("BarCodeScrapped")]
        public async Task<ResultModel<string>> CheckBarCodeScrappedAsync(int barCode, string barCodeNo)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            if (barCodeNo.Length <= 4)
            {
                resultModel.Msg = "內部序號小於4個字數";
                return resultModel;
            }

            var BarCodeInfo = await _context.BarcodeInfoes.Where(w => w.BarcodeID == barCode).FirstOrDefaultAsync();
            if (BarCodeInfo != null)
            {
                if (BarCodeInfo.RuleStatus == "S")
                {
                    resultModel.Msg = $"內部序號【{barCodeNo}】已報廢, 不可繼續過站!";
                    return resultModel;
                }
                if (BarCodeInfo.RuleStatus == "C")
                {
                    resultModel.Msg = $"內部序號【{barCodeNo}】已轉出, 不可繼續過站!";
                    return resultModel;
                }
            }

            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 確認內部條碼流動
        /// </summary>
        /// <param name="wipId">工單號碼ID</param>
        /// <param name="barCode">內部條碼ID</param>
        /// <param name="barCodeNo">內部條碼</param>
        /// <param name="stationID">作業站編號</param>
        /// <returns></returns>
        [HttpGet("BarCodeFlow")]
        private async Task<ResultModel<string>> CheckBarCodeFlowAsync(int wipId, int barCode, string barCodeNo, int stationID)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            var WipInfo = await _context.WipInfos.Where(w => w.WipID == wipId).FirstOrDefaultAsync();

            // 板卡 製程 SMT(S),DIP(D),測試(I),包裝(P)
            var PcbUnitNo = new List<string> { "S", "D", "I", "P" };
            // 系統 製程 組裝(B),測試(T),包裝(O)
            var SystemUnitNo = new List<string> { "B", "T", "O" };

            // 取工單號碼開立的 WipID、生產單位
            var WipInfos = await _context.WipInfos.Where(w => w.WipNO == WipInfo.WipNO).Select(s => new { s.WipID, s.UnitNO }).ToListAsync();

            // 取內部序號過站紀錄
            var BarCodeStations = await _context.BarcodeStation.Where(w => w.BarcodeID == barCode).ToListAsync();

            // 判斷需要前製程是否已經投入
            if (WipInfo.InputFlag == "Y")
            {
                // 有BarCodeID
                if (barCode != 0)
                {
                    // 判斷是否有前製程過站資料
                    // SMT(S)->DIP(D)
                    if (WipInfo.UnitNO == "D")
                    {
                        int? WipID = WipInfos.Where(w => w.UnitNO == "S").Select(s => s.WipID).FirstOrDefault();
                        if (WipID == null)
                        {
                            resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】的前製程生產單位尚未建立工單基本資料";
                            return resultModel;
                        }

                        if (!BarCodeStations.Where(w => w.BarcodeID == barCode && w.WipID == WipID && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = $"該內部序號【{barCodeNo}】前製程生產單位尚未有過站紀錄";
                            return resultModel;
                        }
                    }
                    // DIP(D)->板卡測試(I)
                    else if (WipInfo.UnitNO == "I")
                    {
                        int? WipID = WipInfos.Where(w => w.UnitNO == "D").Select(s => s.WipID).FirstOrDefault();
                        if (WipID == null)
                        {
                            resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】的前製程生產單位尚未建立工單基本資料";
                            return resultModel;
                        }

                        if (!BarCodeStations.Where(w => w.BarcodeID == barCode && w.WipID == WipID && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = $"該內部序號【{barCodeNo}】前製程生產單位尚未有過站紀錄";
                            return resultModel;
                        }
                    }
                    // 板卡測試(I)->板卡包裝(P)
                    else if (WipInfo.UnitNO == "P")
                    {
                        int? WipID = WipInfos.Where(w => w.UnitNO == "I").Select(s => s.WipID).FirstOrDefault();
                        if (WipID == null)
                        {
                            resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】的前製程生產單位尚未建立工單基本資料";
                            return resultModel;
                        }

                        if (!BarCodeStations.Where(w => w.BarcodeID == barCode && w.WipID == WipID && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = $"該內部序號【{barCodeNo}】前製程生產單位尚未有過站紀錄";
                            return resultModel;
                        }
                    }
                    // 組裝(B)->系統測試(T)->成品包裝(O)
                    else if (WipInfo.UnitNO == "T")
                    {
                        int? WipID = WipInfos.Where(w => w.UnitNO == "B").Select(s => s.WipID).FirstOrDefault();
                        if (WipID == null)
                        {
                            resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】的前製程生產單位尚未建立工單基本資料";
                            return resultModel;
                        }

                        if (!BarCodeStations.Where(w => w.BarcodeID == barCode && w.WipID == WipID && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = $"該內部序號【{barCodeNo}】前製程生產單位尚未有過站紀錄";
                            return resultModel;
                        }
                    }
                    else if (WipInfo.UnitNO == "O")
                    {
                        int? WipID = WipInfos.Where(w => w.UnitNO == "T").Select(s => s.WipID).FirstOrDefault();
                        if (WipID == null)
                        {
                            resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】的前製程生產單位尚未建立工單基本資料";
                            return resultModel;
                        }

                        if (!BarCodeStations.Where(w => w.BarcodeID == barCode && w.WipID == WipID && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = $"該內部序號【{barCodeNo}】前製程生產單位尚未有過站紀錄";
                            return resultModel;
                        }
                    }
                }
                // 沒有BarCodeID
                else
                {
                    if (WipInfo.UnitNO != "S" && WipInfo.UnitNO != "B")
                    {
                        resultModel.Msg = $"該工單號碼【{WipInfo.WipNO}】前製程式尚未投產";
                        return resultModel;
                    }
                }
            }

            #region 判斷作業站順序

            // 判斷序號目前是否有重複過站
            var BarcodeInfo = await _context.BarcodeInfoes.Where(w => w.BarcodeID == barCode && w.StationID == stationID && w.WipID == wipId).FirstOrDefaultAsync();
            if (BarcodeInfo != null)
            {
                resultModel.Msg = $"該內部序號【{barCodeNo}】已刷過此站";
                return resultModel;
            }

            resultModel = (ResultModel<string>)await GetBarCodeLastStopRuleStationID(wipId, barCode, stationID, WipInfo.FlowRuleID);
            if (!resultModel.Success)
                return resultModel;

            #endregion
            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 確認內部條碼流動 New
        /// </summary>
        /// <param name="wipNo">工單號碼</param>
        /// <param name="unitNo">製程</param>
        /// <param name="barCodeId">內部條碼ID</param>
        /// <param name="barCodeNo">內部條碼</param>
        /// <param name="stationId">作業站ID</param>
        /// <returns></returns>
        private async Task<ResultModel<string>> CheckBarCodeFlowNew(string wipNo, string unitNo, int barCodeId, string barCodeNo, int stationId)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            int wipId = 0;
            int flowRuleId = 0;
            // 取得工單號碼相關資料 排除沒有流程的工單
            var WipInfos = await _context.WipInfos.Where(w => w.WipNO == wipNo.Trim().ToUpper() &&
                                                              w.FlowRuleID != 0 && w.FlowRuleID != -1)
                                                  .ToListAsync();

            if (WipInfos.Any(w => w.UnitNO == unitNo))
            {
                wipId = WipInfos.Where(w => w.UnitNO == unitNo).FirstOrDefault().WipID;
                flowRuleId = WipInfos.Where(w => w.UnitNO == unitNo).FirstOrDefault().FlowRuleID;
            }
            else
            {
                resultModel.Msg = $"該工單號碼【{wipNo}】找不到工單資料";
                return resultModel;
            }

            // 重工工單不需要判斷 || 製程A的不判斷
            if (!wipNo.StartsWith("6") && !wipNo.StartsWith("5") && unitNo != "A")
            {
                // 板卡 製程 SMT(S),DIP(D),測試(I),包裝(P)
                var PcbUnitNo = new List<string> { "S", "D", "I", "P" };
                // 系統 製程 組裝(B),測試(T),包裝(O)
                var SystemUnitNo = new List<string> { "B", "T", "O" };
                var CheckUnits = new List<string>();
                if (PcbUnitNo.Contains(unitNo))
                    CheckUnits = PcbUnitNo;
                else if (SystemUnitNo.Contains(unitNo))
                    CheckUnits = SystemUnitNo;
                else
                {
                    resultModel.Msg = $"該製程代號【{unitNo}】無法判定是板卡製程或是系統製程";
                    return resultModel;
                }

                // 工單有維護流程的製程
                var WipNoUnits = WipInfos.Select(s => s.UnitNO).Distinct().ToList();
                // 共有的
                var CommonUnits = CheckUnits.Intersect(WipNoUnits).ToList();
                // 將沒有維護流程的製程移除
                CheckUnits.RemoveAll(r => !CommonUnits.Contains(r));
                // 找出目前製程第幾位索引
                var Index = CheckUnits.IndexOf(unitNo);

                // 找不到
                if (Index == -1)
                {
                    resultModel.Msg = $"該製程代號【{unitNo}】請確認是否有維護流程";
                    return resultModel;
                }
                // 索引不是第一位 不是投入製程 需要判斷前面製程是否有資料
                else if (Index != 0)
                {
                    // 取得前面一個製程代號
                    var PreviousUnitNo = CheckUnits[Index - 1];
                    var PreviousWipId = WipInfos.Where(w => w.UnitNO == PreviousUnitNo).FirstOrDefault().WipID;

                    // 找不到該筆內部條碼的前面一個製程紀錄時
                    if (!await _context.BarcodeStation.Where(w => w.BarcodeID == barCodeId && w.WipID == PreviousWipId)
                                                     .AnyAsync())
                    {
                        resultModel.Msg = $"該內部序號【{barCodeNo}】前一個製程尚未投入,請在確認";
                        return resultModel;
                    }
                }
            }

            #region 判斷作業站順序

            // 判斷序號目前是否有重複過站
            var BarcodeInfo = await _context.BarcodeInfoes.Where(w => w.BarcodeID == barCodeId && w.StationID == stationId && w.WipID == wipId).FirstOrDefaultAsync();
            if (BarcodeInfo != null)
            {
                resultModel.Msg = $"該內部序號【{barCodeNo}】已刷過此站";
                return resultModel;
            }

            resultModel = (ResultModel<string>)await GetBarCodeLastStopRuleStationID(wipId, barCodeId, stationId, flowRuleId);
            if (!resultModel.Success)
                return resultModel;

            #endregion
            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 確認工單狀態
        /// </summary>
        /// <param name="wipNo">工單號碼</param>
        /// <param name="unitNo">生產單位</param>
        /// <param name="flowRuleID">流程</param>
        /// <param name="line">線別</param>
        /// <param name="stationID">作業站</param>
        /// <param name="barCodeNo">生產條碼</param>
        /// <returns></returns>
        private async Task<ResultModel<string>> CheckWipNoSationAsync(string wipNo, string unitNo, int flowRuleID, int line, int stationID = 0, string barCodeNo = "")
        {
            ResultModel<string> resultModel = new ResultModel<string>() { Success = false };
            var WipInfo = await _context.WipInfos.Where(w => w.WipNO == wipNo).ToListAsync();

            if (WipInfo.Count() == 0)
            {
                resultModel.Msg = "找不到工單號碼【" + wipNo + "】";
                return resultModel;
            }

            if (!WipInfo.Where(w => w.UnitNO == unitNo).Any())
            {
                resultModel.Msg = "工單號碼【" + wipNo + ",尚未設定此生產單位";
                return resultModel;
            }

            if (!WipInfo.Where(w => w.UnitNO == unitNo && w.LineID == line).Any())
            {
                resultModel.Msg = "工單號碼【" + wipNo + "】,尚未設定此線別";
                return resultModel;
            }

            if (!WipInfo.Where(w => w.UnitNO == unitNo && w.LineID == line && w.FlowRuleID == flowRuleID).Any())
            {
                resultModel.Msg = "工單號碼【" + wipNo + "】,尚未設定此流程站";
                return resultModel;
            }

            // 抓單筆資料
            var item = WipInfo.Where(w => w.UnitNO == unitNo && w.LineID == line).FirstOrDefault();

            if (item.StatusNO == "E")
            {
                resultModel.Msg = $"工單號碼【{item.WipNO}】,該工單已經投入完工,請切換工單";
                return resultModel;
            }

            if (item.StatusNO == "C")
            {
                resultModel.Msg = $"工單號碼【{item.WipNO}】,該工單已刪除,請切換工單";
                return resultModel;
            }

            // 判斷是否是投入站
            var RuleStation = await _context.RuleStations.Where(w => w.FlowRuleID == flowRuleID && w.StationID == stationID)
                             .FirstOrDefaultAsync();
            if (RuleStation != null)
            {
                if (RuleStation.Sequence == 1)
                {
                    var LineInfo = await _context.LineInfoes.Where(w => w.WipNo == item.WipID && w.LineID == item.LineID).FirstOrDefaultAsync();
                    if (LineInfo == null)
                    {
                        //resultModel.Msg = $"工單號碼【{item.WipNO}】,工單尚未開線,不可過站";
                        //return resultModel;

                        //因維修後投入站 不須重開線
                        if (!await _context.BarcodeInfoes.Where(w => w.WipID == item.WipID && w.BarcodeNo == barCodeNo).AnyAsync())
                        {
                            resultModel.Msg = $"工單號碼【{item.WipNO}】,工單尚未開線,不可過站";
                            return resultModel;
                        }
                    }
                }
            }

            // 已投入數量>=工單數量
            if (await CheckNowFirstStation(item.WipID, stationID) == "Y")
            {
                if (item.CompleteQTY >= item.PlanQTY)
                {
                    //因維修後投入站 不須判斷投入數量
                    if (!await _context.BarcodeInfoes.Where(w => w.WipID == item.WipID && w.BarcodeNo == barCodeNo).AnyAsync())
                    {
                        resultModel.Msg = $"工單號碼【{item.WipNO}】,已投入數量>=工單數量,請在確認";
                        return resultModel;
                    }
                }
            }

            // 該筆工單號碼鎖定
            var WipLock = await _context.WipLocks.Where(w => w.WipNO == item.WipNO && w.LockStatus == "0").ToListAsync();
            if (WipLock.Where(w => w.StationID == 0).Any())
            {
                resultModel.Msg = $"工單號碼【{item.WipNO}】,已被鎖定,不可過站";
                return resultModel;
            }

            // StationID = 0 代表批次鎖定
            else if (WipLock.Where(w => w.StationID == stationID).Any())
            {
                resultModel.Msg = $"工單號碼【{item.WipNO}】,工單在當前站別被鎖定,不可過站";
                return resultModel;
            }

            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 判斷序號狀態
        /// </summary>
        /// <param name="barCode">內部序號ID</param>
        /// <param name="barCodeNo">內部序號</param>
        /// <returns></returns>
        [HttpGet("CheckBarCodeStation")]
        public async Task<ResultModel<string>> GetCheckBarCodeStation(int barCode, string barCodeNo)
        {
            ResultModel<string> resultModel = new ResultModel<string>();

            #region 內部序號是否被鎖定
            resultModel = await CheckBarCodeLockAsync(barCode, barCodeNo);
            if (!resultModel.Success)
                return resultModel;
            #endregion

            #region 內部序號是否被報廢
            resultModel = await CheckBarCodeScrappedAsync(barCode, barCodeNo);
            if (!resultModel.Success)
                return resultModel;
            #endregion

            return resultModel;
        }

        /// <summary>
        /// 燒機判斷
        /// </summary>
        /// <param name="wipNo">工單號碼</param>
        /// <param name="barcodeID">內部序號ID</param>
        /// <param name="stationID">作業站ID</param>
        /// <param name="ruleStatus">過站狀態Pass Fail</param>
        /// <returns></returns>
        private async Task<ResultModel<string>> GetCheckBurn(string wipNo, int barcodeID, int stationID, string ruleStatus)
        {
            ResultModel<string> resultModel = new ResultModel<string>() { Success = false };
            // 判斷是否有燒機時間
            var wipBoard = await _context.WipBoards.Where(w => w.WipNo == wipNo).FirstOrDefaultAsync();
            var wipSystem = await _context.WipSystems.Where(w => w.WipNo == wipNo).FirstOrDefaultAsync();
            var wipBoardTime = 0.0;
            var wipSystemTime = 0.0;

            if (wipBoard != null)
            {
                try
                {
                    if (!string.IsNullOrWhiteSpace(wipBoard.BiTime))
                        wipBoardTime = double.Parse(wipBoard.BiTime);

                }
                catch
                {
                    wipBoardTime = -1;
                }
            }

            if (wipSystem != null)
            {
                try
                {
                    if (!string.IsNullOrWhiteSpace(wipSystem.BiTime))
                        wipSystemTime = double.Parse(wipSystem.BiTime);

                }
                catch
                {
                    wipSystemTime = -1;
                }
            }

            if (wipBoardTime <= 0 && wipSystemTime <= 0)
            {
                resultModel.Msg = "請確認燒機時間是否有填寫或者格式有誤";
                return resultModel;
            }

            // 判斷燒機時間是否足夠
            var burnInfo = await _context.BurnInfos.Where(w => w.BarcodeID == barcodeID).ToListAsync();
            if (burnInfo.Count() != 0)
            {
                // 取實際燒機完成時間 空白資料
                var item = burnInfo.Where(w => string.IsNullOrWhiteSpace(w.FinishTime.ToString())).FirstOrDefault();
                if (item != null)
                {
                    // 現在時間 < 預計排程時間
                    if (DateTime.Now < item.ScheduleFinishTime)
                    {
                        // 過站是Fail 不卡燒機時間
                        if (ruleStatus != "F")
                        {
                            resultModel.Msg = "燒機排程完成時間【" + item.ScheduleFinishTime + "】尚未到達";
                            return resultModel;
                        }
                        //// 系統組裝工單 過站是Fail 不卡燒機時間
                        //if (ruleStatus == "F" && wipSystemTime > 0)
                        //{

                        //}
                        //else
                        //{
                        //    resultModel.Msg = "燒機排程完成時間【" + item.ScheduleFinishTime + "】尚未到達";
                        //    return resultModel;
                        //}
                    }
                }
                else // 燒機資料都有填入實際燒機時間
                {
                    resultModel.Msg = "BurnIn";
                }
            }
            else
            // 沒有BurnInfo = Burn In
            {
                resultModel.Msg = "BurnIn";
            }
            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 確認組件狀態
        /// </summary>
        /// <returns></returns>
        [HttpGet("BarCodeKP")]
        private async Task<ResultModel<WipKp>> CheckBarCodeKeyPartsData([FromQuery] BarcodeItemKPDto data)
        {
            ResultModel<WipKp> resultModel = new ResultModel<WipKp> { Success = false };
            // 更新WipKp字元長度
            var UpdateWipKpLength = new List<WipKp>();
            try
            {
                // 抓 工單key Parts資料
                var wipKps = _context.WipKps.Where(w => w.WipNo == data.wipNo && w.UnitNo == data.unitNo)
                                             .OrderBy(o => o.KpSeq).ToList();
                if (wipKps.Count != 0)
                {
                    // 取料號組件資料
                    var BarCodeItems = _context.BarcodeItems.Where(w => w.BarcodeID == data.barCode &&
                                                                              w.S.UnitNo == data.unitNo &&
                                                                              w.WipID == data.wipId).ToList();

                    // 當前組件數量+已存料號組件數量 > 工單綁定組件數量
                    if (data.inputKP.Count + BarCodeItems.Count > wipKps.Count)
                    {
                        resultModel.Msg = "組件數量已刷超過設定數量,請確認";
                        return resultModel;
                    }

                    #region 比對組件資料

                    var CheckMsg = string.Empty;
                    int x = BarCodeItems.Count;

                    // 紀錄刷入KP不可重複序號,後續判斷刷入KP有重複
                    var CheckInputKp = new List<BarCodeCheckDto.inputItem>();

                    for (int i = 0; i < data.inputKP.Count; i++)
                    {
                        // 按照順序
                        var wipKpsItem = wipKps[x + i];
                        var dataItem = data.inputKP[i];
                        // 有KpNo以KpNo為主
                        if (!string.IsNullOrWhiteSpace(dataItem.inputType))
                        {
                            wipKpsItem = wipKps.Where(w => w.KpNo.ToUpper() == dataItem.inputType.ToUpper()).FirstOrDefault();

                            if (wipKpsItem == null)
                            {
                                wipKpsItem = wipKps[x + i];
                            }
                        }

                        CheckMsg += await CheckKeyPartsCorrect(wipKpsItem, dataItem);

                        // 子件綁入的字元數用該工單第一筆子件字元數為基準, 後續不符字數卡控
                        // 如果該筆KP長度是0 or Null 就更新長度
                        if (wipKpsItem.Length == null || wipKpsItem.Length == 0)
                        {
                            // 排除MAC
                            if (!wipKpsItem.KpNo.StartsWith("MAC"))
                            {
                                wipKpsItem.Length = dataItem.inputData.Trim().Length;
                                UpdateWipKpLength.Add(wipKpsItem);
                            }
                        }

                        // 不可重複在紀錄(刷入kp判斷重複)
                        if (wipKpsItem.IsRepeat == "N")
                        {
                            CheckInputKp.Add(dataItem);
                        }
                    }

                    // 有錯誤訊息
                    if (!string.IsNullOrWhiteSpace(CheckMsg))
                    {
                        resultModel.Msg = CheckMsg;
                        return resultModel;
                    }

                    // 刷入KP有重複
                    var RepeatKp = CheckInputKp
                        .GroupBy(g => g.inputData)
                        .Where(group => group.Count() > 1)
                        .Select(group => group.Key);

                    if (RepeatKp.Count() != 0)
                    {
                        resultModel.Msg = $"刷入組件序號有重複【{string.Join(',', RepeatKp)}】</br>";
                        return resultModel;
                    }

                    #endregion
                }

                // 確認沒問題後
                resultModel.Data = UpdateWipKpLength;
                resultModel.Success = true;
                return resultModel;
            }
            catch (Exception ex)
            {
                resultModel.Success = false;
                resultModel.Msg = ex.Message;
                return resultModel;
            }
        }

        /// <summary>
        /// 確認治具狀態
        /// </summary>
        /// <returns></returns>
        private ResultModel<string> CheckBarCodeOutfit([FromQuery] List<BarCodeCheckDto.Outfit> outfit)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };
            foreach (var outfitNo in outfit)
            {
                // 治具
                var q = _context.OutfitInfoes.Where(w => w.OutfitNo.ToUpper().Trim() == outfitNo.inputData.ToUpper().Trim()).FirstOrDefault();

                if (q == null)
                {
                    resultModel.Msg = $"中央治具找不到該治具編號【{outfitNo.inputData}】";
                    return resultModel;
                }

            }
            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 取得上一個作業站RuleStationID
        /// </summary>
        /// <param name="wipID">工單ID</param>
        /// <param name="barCodeID">BarCodeID</param>
        /// <param name="stationID">目前作業站ID</param>
        /// <param name="flowRuleID">工單流程ID</param>
        /// <returns>true:false</returns>
        private async Task<IResultModel> GetBarCodeLastStopRuleStationID(int wipID, int barCodeID, int stationID, int flowRuleID)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };

            // 用作業站抓 有設定下一站為該站的資料
            var Rules = await _context.Ruleses.Where(w => w.FlowRuleID == flowRuleID).ToListAsync();
            // 取得目前BarCodeInfo 站別
            var BarCodeInfo = await _context.BarcodeInfoes.Where(w => w.BarcodeID == barCodeID).FirstOrDefaultAsync();

            if (Rules.Count() == 0)
            {
                resultModel.Msg = "找不到該筆工單流程之流程設定相關資料,請確認";
                return resultModel;
            }
            else
            {
                // 有過站紀錄
                if (BarCodeInfo != null)
                {
                    // 如果BarCodeInfo 結案,判斷當下作業站是否第一站
                    if (BarCodeInfo.StatusID == -1)
                    {
                        if (BarCodeInfo.WipID == wipID)
                        {
                            resultModel.Msg = "該內部序號在目前生產製程已完工,請確認";
                            return resultModel;
                        }

                        if (!Rules.Where(w => w.StationID == stationID && w.RuleSeq == 1 && w.RuleStatus == "P").Any())
                        {
                            resultModel.Msg = "目前作業站不是第一站,請確認";
                            return resultModel;
                        }
                        resultModel.Success = true;
                        return resultModel;
                    }

                    if (BarCodeInfo.WipID != wipID)
                    {
                        resultModel.Msg = $"前一製程還未結束,請確認";
                        return resultModel;
                    }

                    // 目前BarCodeInfo StationID 取得相對應下個流程StationID
                    var rulesByBarCodeInfoStationID = Rules.Where(w => w.StationID == BarCodeInfo.StationID).ToList();

                    // 當下個流程 != 目前過站流程
                    if (rulesByBarCodeInfoStationID.Where(w => w.NextStationID == stationID && w.RuleStatus == BarCodeInfo.RuleStatus).Count() == 0)
                    {
                        var Nextstation = rulesByBarCodeInfoStationID.Where(w => w.RuleStatus == BarCodeInfo.RuleStatus).ToList();
                        var StationName = Nextstation.Select(s => s.NextStation.StationName).ToArray();
                        resultModel.Msg = "該內部序號下一個作業站應該是:" + string.Join('、', StationName) + " ,請確認";
                        return resultModel;
                    }
                }
                // 沒有過站紀錄 判斷是否為投入站
                else
                {
                    if (!Rules.Where(w => w.StationID == stationID && w.RuleSeq == 1 && w.RuleStatus == "P").Any())
                    {
                        resultModel.Msg = "該內部序號尚未投入,請確認";
                        return resultModel;
                    }
                }
            }
            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 確認下一站為完工
        /// </summary>
        /// <param name="flowRuleId">流程ID</param>
        /// <param name="stationID">作業站ID</param>
        /// <param name="ruleStatus">過站狀態 Pass or Fail</param>
        /// <returns>Success(true)是 (false)不是</returns>
        [HttpGet("CheckNextStopCloseStation")]
        public async Task<ResultModel<string>> CheckNextStopCloseStation(int flowRuleId, int stationID, string ruleStatus)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };

            // 取得流程
            var ruleStations = await _context.RuleStations.Where(w => w.FlowRuleID == flowRuleId).ToListAsync();
            if (ruleStations.Any())
            {
                // 在RuleStation 找不到該作業站
                if (!ruleStations.Where(w => w.StationID == stationID).Any())
                    return resultModel;

                var rules = await _context.Ruleses.Where(w => w.FlowRuleID == flowRuleId).ToListAsync();

                // 當下一站SatationID= 1000 代表完工站
                if (rules.Where(w => w.StationID == stationID && w.NextStationID == 1000 && w.RuleStatus == ruleStatus).Any())
                {
                    resultModel.Success = true;
                    return resultModel;
                }
            }
            return resultModel;
        }

        /// <summary>
        /// 確認目前該站是否為第一站
        /// </summary>
        /// <param name="wipId">工單號碼ID</param>
        /// <param name="stationID">作業站ID</param>
        /// <returns>Y:是 N:不是</returns>
        private async Task<string> CheckNowFirstStation(int wipId, int stationID)
        {
            var WipInfo = await _context.WipInfos.Where(w => w.WipID == wipId).FirstOrDefaultAsync();

            if (WipInfo != null)
            {
                // 取得流程
                var ruleStations = await _context.RuleStations.Where(w => w.FlowRuleID == WipInfo.FlowRuleID).ToListAsync();
                if (ruleStations.Count() != 0)
                {
                    // 用目前站別判斷順序是不是 1
                    if (ruleStations.Where(w => w.StationID == stationID && w.Sequence == 1 && w.StationType == "M").Any())
                        return "Y";
                }
            }
            return "N";
        }

        /// <summary>
        /// 判斷生產中工單是否已經全部完工 自動更新
        /// </summary>
        /// <param name="wipId">工單ID</param>
        /// <returns></returns>
        [HttpGet("CheckWipNoBarCodeAllClost")]
        public async Task<string> CheckWipNoBarCodeAllClost(int wipId)
        {
            var wipInfo = await _context.WipInfos.Where(w => w.WipID == wipId).FirstOrDefaultAsync();

            if (wipInfo != null)
            {
                // 取Rules 最後一站為完工站的Station及狀態 
                var rules = await _context.Ruleses.Where(w => w.FlowRuleID == wipInfo.FlowRuleID).ToListAsync();
                var lastStation = rules.Where(w => w.NextStationID == 1000).Select(s => new { s.StationID, s.RuleStatus }).ToList();

                var barcodeStations = await _context.BarcodeStation.Where(w => w.WipID == wipId).ToListAsync();

                // ByLastStation Count = 工單數 (完工)
                var closeWipQty = 0;
                foreach (var item in lastStation)
                {
                    closeWipQty += barcodeStations.Where(w => item.StationID == w.StationID && item.RuleStatus == w.RuleStatus)
                                                  .Select(s => s.BarcodeID).Distinct().Count();
                }

                if (wipInfo.PlanQTY == closeWipQty)
                {
                    WipInfosController wipInfosController = new WipInfosController(_context);
                    var result = await wipInfosController.PutWipinfoToStatusNO(wipId, "E");
                }
            }
            return "";
        }

        /// <summary>
        /// 無序號工單批次作業
        /// </summary>
        /// <param name="WipID"></param>
        /// <returns></returns>
        [HttpGet("CreateBarcodeInfobyPCS038")]
        public async Task<IResultModel> CreateBarcodeInfobyPCS038(int WipID)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = true };

            var wipinfo = await _context.WipInfos.Where(w => w.WipID == WipID).FirstOrDefaultAsync();
            if (wipinfo != null)
            {
                var wipbarcode = await _context.WipBarcodes.Where(w => w.WipNO == wipinfo.WipNO).ToListAsync();
                string resultMsg = "";
                if (wipbarcode.Count() != 0)
                {
                    // 取BarCodeID
                    Helper helper = new Helper(_context);
                    foreach (var item in wipbarcode)
                    {
                        string start = item.StartNO;
                        string end = item.EndNO;

                        // 取得流水號的長度
                        int serialLength = start.Length - 4;

                        // 將起始跟結束序號的流水號轉換為數字
                        int startSerial = int.Parse(start.Substring(start.Length - 4));
                        int endSerial = int.Parse(end.Substring(end.Length - 4));

                        // 進行序號展開
                        for (int i = startSerial; i <= endSerial; i++)
                        {
                            string serial = i.ToString().PadLeft(4, '0');
                            string code = start.Substring(0, start.Length - 4);

                            string barcode = code + serial;
                            BarCodeCheckDtoForDBData data = new BarCodeCheckDtoForDBData();
                            data.unitNo = wipinfo.UnitNO;
                            data.wipID = WipID;
                            data.barcode = barcode;
                            data.barcodeID = 0;
                            data.extNo = "";
                            data.flowRule = wipinfo.FlowRuleID;
                            data.wipNo = wipinfo.WipNO;
                            var Msg = Table_BarcodeInfo(data, await helper.GetIDKey("BARCODE_ID"));

                            if (string.IsNullOrWhiteSpace(Msg))
                            {
                                resultMsg += $"{code + serial} 內部條碼:產生成功!!!" + "</br>";
                            }
                            else
                            {
                                resultMsg += $"{code + serial} 內部條碼:產生失敗!!!原因:" + Msg + "</br>";
                            }
                        }

                        resultModel.Success = true;
                    }
                }
                else
                {
                    resultModel.Success = false;
                    resultModel.Msg = "工單資料沒有設定生產序號區間";
                }
            }
            else
            {
                resultModel.Success = false;
                resultModel.Msg = "查無工單";
            }
            return resultModel;
        }

        /// <summary>
        /// 確認治具是否已達到預警提前次數
        /// </summary>
        /// <param name="WipNo"></param>
        private void CheckOutfitAlert(string WipNo)
        {

        }

        /// <summary>
        /// 確認過站基本欄位是否填寫
        /// </summary>
        /// <param name="barCodeCheckDto"></param>
        /// <returns></returns>
        private string CheckBarCodeInputData(BarCodeCheckDto barCodeCheckDto)
        {
            string Msg = string.Empty;
            if (string.IsNullOrWhiteSpace(barCodeCheckDto.wipNo))
                Msg += "請輸入工單號碼,";

            if (string.IsNullOrWhiteSpace(barCodeCheckDto.barcode))
                Msg += "請輸入內部條碼,";

            if (string.IsNullOrWhiteSpace(barCodeCheckDto.unitNo))
                Msg += "請輸入生產單位,";

            if (barCodeCheckDto.stationID == 0)
                Msg += "請輸入作業站代碼,";

            if (barCodeCheckDto.line == 0)
                Msg += "請輸入線別代碼,";

            // 判斷User存在
            if (barCodeCheckDto.userID != 0)
            {
                if (_context.UserInfoes.Where(w => w.UserID == barCodeCheckDto.userID).Count() == 0)
                    Msg += $"找不到UserID【{barCodeCheckDto.userID}】資料,";
            }

            if (!string.IsNullOrWhiteSpace(Msg))
                Msg = Msg.Substring(0, Msg.Length - 1);

            return Msg;
        }

        /// <summary>
        /// 過站相關資訊 寫入
        /// </summary>
        /// <param name="barCodeCheckDto"></param>
        /// <returns></returns>
        private async Task<BarCodeCheckDtoForDBData> PassIngDataTuck(BarCodeCheckDto barCodeCheckDto)
        {
            var result = new BarCodeCheckDtoForDBData();

            result.wipNo = barCodeCheckDto.wipNo.Trim().ToUpper();
            result.barcode = barCodeCheckDto.barcode.Trim().ToUpper();
            result.barcodeType = barCodeCheckDto.barcodeType;
            result.unitNo = barCodeCheckDto.unitNo;
            result.stationID = barCodeCheckDto.stationID;
            result.line = barCodeCheckDto.line;
            result.userID = barCodeCheckDto.userID;


            #region 相關資料 Null給空白
            // KP||NG Input
            if (barCodeCheckDto.inputItems == null)
                result.inputItems = new List<BarCodeCheckDto.inputItem>();
            else
            {
                result.inputItems = barCodeCheckDto.inputItems.Where(w => !string.IsNullOrWhiteSpace(w.inputType)).ToList();
                result.inputItems = result.inputItems.Select(s =>
                {
                    s.inputData = s.inputData.Trim().ToUpper();
                    return s;
                }).ToList();
            }

            // 治具 Input
            if (barCodeCheckDto.outfits == null)
                result.outfits = new List<BarCodeCheckDto.Outfit>();
            else
            {
                result.outfits = barCodeCheckDto.outfits.Where(w => !string.IsNullOrWhiteSpace(w.inputData)).ToList();
                result.outfits = result.outfits.Select(s =>
                {
                    s.inputData = s.inputData.Trim().ToUpper();
                    return s;
                }).ToList();
            }


            // 更新Kp先給空白
            result.UpdateWipKpLenght = new List<WipKp>();
            #endregion

            // 工單資料
            var WipInfo = await _context.WipInfos.Where(w => w.WipNO == barCodeCheckDto.wipNo &&
                                                             w.UnitNO == barCodeCheckDto.unitNo &&
                                                             w.LineID == barCodeCheckDto.line).FirstOrDefaultAsync();
            if (WipInfo != null)
            {
                result.wipID = WipInfo.WipID;
                result.flowRule = WipInfo.FlowRuleID;
            }

            // 料號
            var WipAtt = await _context.WipAtts.Where(w => w.WipNO == barCodeCheckDto.wipNo.Trim().ToUpper()).FirstOrDefaultAsync();
            if (WipAtt != null)
            {
                result.itemNo = WipAtt.ItemNO;
                var MaterialItem = await _context.MaterialItems.Where(w => w.ItemNo == result.itemNo).FirstOrDefaultAsync();
                if (MaterialItem != null)
                {
                    // 料號ID 
                    result.item = MaterialItem.ItemID;
                }
            }

            // 工作站
            var Station = await _context.Stationses.Where(w => w.StationID == result.stationID).FirstOrDefaultAsync();
            if (Station != null)
            {
                result.stations_TestType = Station.TestType;
                result.stations_TypeNo = Station.TypeNo;
                result.stations_Name = Station.StationName;
            }

            // 生產單位_簡碼
            var FactoryUnit = await _context.FactoryUnits.Where(w => w.UnitNo == result.unitNo).FirstOrDefaultAsync();
            if (FactoryUnit != null)
            {
                result.factoryUnit_UnitCode = FactoryUnit.UnitCode;
            }

            // 判斷序號為出貨條碼,並轉成內部條碼
            var BarCodeInfo = await _context.BarcodeInfoes.Where(w => w.ExtraBarcodeNo == barCodeCheckDto.barcode.Trim().ToUpper()).FirstOrDefaultAsync();
            if (BarCodeInfo != null)
            {
                result.extNo = BarCodeInfo.ExtraBarcodeNo;
                result.barcode = BarCodeInfo.BarcodeNo;
            }

            // 抓BarCode ID
            BarCodeInfo = await _context.BarcodeInfoes.Where(w => w.BarcodeNo == result.barcode).FirstOrDefaultAsync();
            if (BarCodeInfo != null)
            {
                result.barcodeID = BarCodeInfo.BarcodeID;
            }

            // 取工單板卡資訊-錫膏
            var WipBoard = await _context.WipBoards.Where(w => w.WipNo == barCodeCheckDto.wipNo.Trim().ToUpper()).FirstOrDefaultAsync();
            if (WipBoard != null)
            {
                result.wipBoard_SolderPaste = WipBoard.SolderPaste;
            }

            // 過站狀態
            if (result.inputItems.Where(w => w.inputData.Contains("$")).Any())
                result.ruleStatus = "F";
            else
                result.ruleStatus = "P";

            return result;
        }

        /// <summary>
        /// 確認過站資料是否正確
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task<string> CheckPassIngDataCorrect(BarCodeCheckDtoForDBData data)
        {
            string Msg = string.Empty;

            if (data.wipID == 0)
                Msg += $"找不到工單號碼【{data.wipNo}】相關工單資料,請確認,";

            if (data.flowRule == 0)
                Msg += $"工單號碼【{data.wipNo}】尚未設定流程,請確認,";

            // 抓流程順序資料
            var ruleStations = await _context.RuleStations.Where(w => w.FlowRuleID == data.flowRule).ToListAsync();
            if (ruleStations.Count() == 0)
            {
                Msg += $"該工單號碼【{data.wipNo}】的流程編號尚未設定流程";
            }
            else
            {
                if (!ruleStations.Where(w => w.StationID == data.stationID).Any())
                {
                    Msg += $"該工單號碼【{data.wipNo}】的流程未設定此作業站";
                }
            }

            // 判斷有無不良代碼
            if (data.inputItems.Where(w => w.inputData.Contains("$")).Any())
            {
                var NgItem = data.inputItems.Where(w => w.inputData.Contains("$")).ToList();
                IQueryable<NGReason> q = _context.NGReasons;
                foreach (var item in NgItem.Select(s => s.inputData))
                {
                    if (!q.Where(w => w.NGReasonNo.Trim().ToUpper() == item.Replace("$", "").Trim().ToUpper()
                                      && w.Status == "A").Any())
                    {
                        Msg += $"查無不良代碼【{item.Replace("$", "").Trim().ToUpper()}】,請確認,";
                    }
                }
            }

            // 維修過站資料判斷
            if (data.barcodeType == "S")
            {
                // 確認新舊組件序號是否都有值
                if (data.inputItems.Where(w => w.inputType.ToUpper() != "NG" &&
                (string.IsNullOrWhiteSpace(w.inputData) || string.IsNullOrWhiteSpace(w.oldInputData))).Any())
                {
                    Msg += "工單號碼【" + data.wipNo + "】維修過站資料有缺新舊組件序號,請確認,";
                }
            }

            if (!string.IsNullOrWhiteSpace(Msg))
                Msg = Msg.Substring(0, Msg.Length - 1);

            return Msg;
        }

        /// <summary>
        /// KeyPart 細項判斷確認
        /// </summary>
        /// <param name="wipKp">工單組件資料</param>
        /// <param name="inputItem">過站刷入組件資料</param>
        /// <returns></returns>
        private async Task<string> CheckKeyPartsCorrect(WipKp wipKp, BarCodeCheckDto.inputItem inputItem)
        {
            string CheckMsg = string.Empty;
            #region 比對序號長度是否正確

            if (wipKp.Length != null)
            {
                if (wipKp.Length != inputItem.inputData.Length && wipKp.Length != 0)
                    CheckMsg += "組件序號【" + inputItem.inputData + "】 與組件名稱【" + wipKp.KpName + "】長度不符合</br>";
            }

            #endregion

            #region 前置碼正確

            if (!string.IsNullOrWhiteSpace(wipKp.Title))
            {
                if (!inputItem.inputData.ToUpper().StartsWith(wipKp.Title.ToUpper()))
                    CheckMsg += "組件序號【" + inputItem.inputData + "】 與組件名稱【" + wipKp.Title + "】前置碼不符合</br>";
            }
            #endregion

            #region 組件代碼-組件序號是否重複

            // 判斷KP是否重複=N
            if (wipKp.IsRepeat == "N")
            {
                if (await _context.BarcodeItems.AsNoTracking().Where(w => w.PartNo == inputItem.inputData.ToUpper().Trim()).AnyAsync())
                {
                    CheckMsg += "組件名稱【" + wipKp.KpName + "】已有相同組件序號【" + inputItem.inputData + "】紀錄 </br>";
                }
            }

            #endregion

            #region 判斷組件序號是否在製狀態

            if (wipKp.KpNo.ToUpper() == "04")
            {
                if (await _context.BarcodeInfoes.Where(w => w.BarcodeNo == inputItem.inputData.ToUpper().Trim() && w.StatusID != -1).AnyAsync())
                {
                    CheckMsg += "組件序號【" + inputItem.inputData + "】 目前是在製狀態</br>";
                }
            }

            #endregion

            #region 判斷MAC區間

            // 安勤不需要判斷MAC區間
            if (wipKp.KpNo.ToUpper().StartsWith("MAC"))
            {
                var wipMAC = await _context.WipMACs.Where(w => w.WipNO == wipKp.WipNo).ToListAsync();
                if (wipMAC.Count() == 0)
                {
                    CheckMsg += "工單號碼【" + wipKp.WipNo + "】 找不到綁定MAC區間</br>";
                }
                else
                {
                    // 判斷是否符合區間
                    if (inputItem.inputData.Length != 12 && inputItem.inputData.Length != 6)
                    {
                        CheckMsg += "組件序號【" + inputItem.inputData + "】 綁定MAC不足12碼或6碼 </br>";
                    }
                    else
                    {
                        // 長度12碼 判斷前置碼
                        if (inputItem.inputData.Length == 12)
                        {
                            if (!wipMAC.Where(w => inputItem.inputData.StartsWith(w.Title)).Any())
                            {
                                CheckMsg += $"組件序號【{inputItem.inputData}】與MAC【{string.Join('、', wipMAC.Select(s => s.Title).ToList())}】前置碼不符合 </br>";
                            }
                        }
                        // 長度6碼 抓WIPMAC 前6碼補足 12碼
                        else if (inputItem.inputData.Length == 6)
                        {
                            var wipMacItem = wipMAC.FirstOrDefault();
                            inputItem.inputData = wipMacItem.Title + inputItem.inputData;
                        }

                        var InputMacTitle = inputItem.inputData.Substring(0, 6).ToUpper();
                        var InputMacNo = Convert.ToInt32(inputItem.inputData.Substring(6, 6), 16);
                        if (!wipMAC.Where(w => Convert.ToInt32(w.StartNO, 16) <= InputMacNo &&
                                              InputMacNo <= Convert.ToInt32(w.EndNO, 16) &&
                                              w.Title == InputMacTitle).Any())
                        {
                            CheckMsg += "組件序號【" + inputItem.inputData + "】 與工單設定MAC區間不符合 </br>";
                        }
                    }
                }
            }

            #endregion

            #region 判斷出貨序號

            // 當KP_NAME是 EXT_NO 判斷組件-出貨序號 是否有在區間
            if (wipKp.KpNo.ToUpper() == "95")
            {
                WipBarcodeOtherController wipBarcodeOtherController = new WipBarcodeOtherController(_context);
                var WipBarCodeOther = await wipBarcodeOtherController.CheckWipBarcodeOtherByNo(wipKp.WipNo, inputItem.inputData);
                if (WipBarCodeOther.Value.Count() == 0)
                {
                    CheckMsg += "組件序號【" + inputItem.inputData + "】 與工單設定出貨序號區間不符合 </br>";
                }
            }

            #endregion

            return CheckMsg;
        }

        /// <summary>
        /// 更新 組件替換資料
        /// </summary>
        /// <param name="barcodeItems">料號組件資料</param>
        /// <param name="barcodeItemChanges">料號組件更換資料</param>
        /// <returns></returns>
        private async Task<string> UpdateBarCodeItemChange(List<BarcodeItem> barcodeItems, List<BarcodeItemChange> barcodeItemChanges)
        {
            string Msg = string.Empty;
            using (var tran = _context.Database.BeginTransaction())
            {
                try
                {
                    // 更新料號組件
                    foreach (var item in barcodeItems)
                    {
                        _context.Entry(item).State = EntityState.Modified;
                        await _context.SaveChangesAsync();
                    }

                    // 新增料號組件更換資料
                    foreach (var item in barcodeItemChanges)
                    {
                        Helper helper = new Helper(_context);
                        item.BarcodeItemChangeID = await helper.GetIDKey("BARCODE_ITEM_CHANGE");
                        _context.BarcodeItemChanges.Add(item);

                        await _context.SaveChangesAsync();
                    }
                    await tran.CommitAsync();
                }
                catch (Exception ex)
                {
                    Msg = $"過站新增系統錯誤:{ex.Message}";
                    await tran.RollbackAsync();
                }
            }
            return Msg;
        }

        /// <summary>
        /// 取該筆工單流水碼
        /// </summary>
        /// <param name="wipNo">工單號碼</param>
        /// <returns></returns>
        private async Task<int> GetWipNoSerialNumber(string wipNo)
        {
            int snLen = 4;
            try
            {
                var result_WipInfo = await _context.WipInfos.Where(w => w.WipNO == wipNo.Trim().ToUpper()).ToListAsync();
                // 取工單號碼最大工單數量
                snLen = result_WipInfo.Max(m => m.PlanQTY).ToString().Length;
                // 長度最小取4碼
                if (snLen <= 4) snLen = 4;
            }
            catch
            {
                return snLen;
            }
            return snLen;
        }

        /// <summary>
        /// 確認SMT過站刷入鋼板編號 錫膏編號
        /// </summary>
        /// <returns></returns>
        private ResultModel<string> CheckSmtSkip(BarCodeCheckDtoForDBData data)
        {
            ResultModel<string> resultModel = new ResultModel<string> { Success = false };

            // 沒有過站治具資料
            if (!data.outfits.Any())
            {
                resultModel.Msg = $"SMT過站 請刷入鋼板編號及錫膏編號 ";
                return resultModel;
            }

            // 鋼板
            var result_SteelPlate = _context.SteelPlateInfos.Where(w => w.Items.ToUpper().Contains(data.itemNo)
                                                                     && w.Status == "1");
            if (data.stations_Name == "SMT_TOP")
                result_SteelPlate = result_SteelPlate.Where(w => w.Items.ToUpper().Contains(data.itemNo + "_A"));
            else
                result_SteelPlate = result_SteelPlate.Where(w => w.Items.ToUpper().Contains(data.itemNo + "_B") ||
                                                                 w.Items.ToUpper().Contains(data.itemNo + "_AB"));

            if (!result_SteelPlate.Any())
            {
                resultModel.Msg = $"鋼板資料查無有綁定該筆工程編號【{data.itemNo}】";
                return resultModel;
            }

            // 紀錄鋼板及錫膏是否都有資料
            bool checkSteelPlate = false;
            bool checkSolderPaste = false;
            foreach (var item in data.outfits)
            {
                // 鋼板
                var steelPlateID = result_SteelPlate.Where(w => w.SteelPlateNo.Trim().ToUpper() == item.inputData.Trim().ToUpper())
                                                    .Select(s => s.SteelPlateID).ToList();
                if (steelPlateID.Any())
                {
                    checkSteelPlate = true;
                    // 查詢鋼板紀錄沒有上線紀錄
                    if (!_context.SteelPlateMeasures.Where(w => steelPlateID.Contains(w.SteelPlateID)
                                                                && w.OffUserID == null).Any())
                    {
                        resultModel.Msg = $"鋼板編號【{item.inputData}】 沒有上線量測紀錄";
                        return resultModel;
                    }
                }

                // 工程資訊-錫膏
                var solderPaste = _context.SolderPasteInfos.Where(w => w.SolderPasteNo.ToUpper() == item.inputData.ToUpper().Trim()
                                                             && (w.Status == "O" || w.Status == "U")).FirstOrDefault();

                if (solderPaste != null)
                {
                    checkSolderPaste = true;
                    // 錫膏 A:S3X58-M406-3 , B:M705-221BM5-32-11.5K3 , C:M705-S101ZH-S4 , E:M705-GRN360-K2-V , D:NA
                    if (data.wipBoard_SolderPaste != "D")
                    {
                        var wipSolderPaste = string.Empty;
                        switch (data.wipBoard_SolderPaste)
                        {
                            case "A":
                                wipSolderPaste = "S3X58-M406-3";
                                break;
                            case "B":
                                wipSolderPaste = "M705-221BM5-32-11.5K3";
                                break;
                            case "C":
                                wipSolderPaste = "M705-S101ZH-S4";
                                break;
                            case "E":
                                wipSolderPaste = "M705-GRN360-K2-V";
                                break;
                        }
                        if (solderPaste.Description.Trim().ToUpper() != wipSolderPaste)
                        {
                            resultModel.Msg = $"錫膏編號【{item.inputData}】該筆工單維護錫膏規格不一致";
                            return resultModel;
                        }
                    }

                    // 查詢錫膏紀錄出冰箱紀錄
                    var Record = _context.SolderPasteRecords.Where(w => w.SolderPasteID == solderPaste.SolderPasteID
                                                                        && w.Status == "O")
                                                                        .FirstOrDefault();
                    if (Record == null)
                    {
                        resultModel.Msg = $"錫膏編號【{item.inputData}】 沒有出冰箱紀錄";
                        return resultModel;
                    }
                    // 錫膏編號必須為出冰箱2hrs後才可投入生產
                    else if (Record.CreateDate > DateTime.Now.AddHours(-2))
                    {
                        resultModel.Msg = $"錫膏編號【{item.inputData}】出冰箱尚未超過2Hrs";
                        return resultModel;

                    }
                }
            }

            if (!checkSteelPlate)
            {
                resultModel.Msg = $"請確認是否有輸入正確鋼板編號";
                return resultModel;
            }

            if (!checkSolderPaste)
            {
                resultModel.Msg = $"請確認是否有輸入正確錫膏編號";
                return resultModel;
            }

            resultModel.Success = true;
            return resultModel;
        }

        /// <summary>
        /// 鋼板目前已使用次數超過95%,Mail通知
        /// </summary>
        private async void SteelPlateUse95Mail(SteelPlateInfo steelPlateInfo)
        {
            string MailGroup = "STEEL_ALARM";
            string Subject = $"[AMES系統通知] 鋼板已使用次數超過95%通知";
            string Body = $"鋼板編號:{steelPlateInfo.SteelPlateNo}<br/>" +
                          $"量測日期[{DateTime.Now:yyyy/MM/dd}]<br/>" +
                          $"量測時間[{DateTime.Now:HH:mm:ss}]<br/>" +
                          $"鋼板可使用次數[{steelPlateInfo.UsedTimes}]<br/>" +
                          $"目前已使用次數[{steelPlateInfo.BeUseTimes}]<br/>";


            await new MailController(_context, _config).PostMail(Subject, Body, MailGroup, "", false);

            WipAlarmsController wipAlarmsController = new WipAlarmsController(_context);
            WipAlarm wipAlarm = new WipAlarm();
            wipAlarm.AlarmTypeID = (int)EnumWipAlarm.EnumTypeId.SteelPlateNg;
            wipAlarm.WipNO = steelPlateInfo.SteelPlateNo;
            wipAlarm.AlarmParam = steelPlateInfo.Status;
            wipAlarm.AlarmValue = "1";
            wipAlarm.AlarmDesc = Subject;
            wipAlarm.AlarmDateTime = DateTime.Now;
            await wipAlarmsController.PostWipAlarm(wipAlarm);


        }

        /// <summary>
        /// 確認KP是否重複
        /// </summary>
        /// <param name="wipNo">工單號碼</param>
        /// <param name="kpNo">KP料號</param>
        /// <param name="unitNo">生產單位</param>
        /// <param name="partNo">刷入KP條碼</param>
        /// <returns>true:KP條碼重複,false:表示不重複</returns>
        private bool SecondDuplicateCheckKP(string wipNo, string kpNo, string unitNo, string partNo)
        {
            var query = @" SELECT 1 AS RESULT FROM DUAL
                                        WHERE EXISTS (              -- 確認KP設定不能重複
                                            SELECT 1 FROM JHAMES.WIP_KP
                                            WHERE WIP_NO = :WipNo 
                                            AND KP_NO = :KpNo
                                            AND UNIT_NO = :UnitNo
                                            AND IS_REPEAT = 'N'
                                        )
                                        AND EXISTS (
                                            SELECT 1 
                                            FROM JHAMES.BARCODE_ITEM
                                            WHERE PART_NO = :PartNo
                                        )";
            DynamicParameters p = new DynamicParameters();
            p.Add("WipNo", wipNo);
            p.Add("KpNo", kpNo);
            p.Add("UnitNo", unitNo);
            p.Add("WipNo", wipNo);
            p.Add("PartNo", partNo);
            var result = _context.Database.DapperQuery<dynamic>(query, p);

            if (result.Any())
                return true;
            else
                return false;
        }
    }
}