kazelee
2025-05-13 38a8b2931abd72ee04285794aacbea7ed7c49228
Services/MoboxService.cs
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HH.WCS.Mobox3.DSZSH.Consts;
using HH.WCS.Mobox3.DSZSH.Helper;
using HH.WCS.Mobox3.DSZSH.Helpers;
using HH.WCS.Mobox3.DSZSH.Helpers.Model;
using HH.WCS.Mobox3.DSZSH.Models;
using Newtonsoft.Json;
using SqlSugar;
using static HH.WCS.Mobox3.DSZSH.Dtos.Request.MoboxRequest;
using static HH.WCS.Mobox3.DSZSH.Dtos.Response.MoboxResponse;
@@ -383,29 +387,168 @@
            }
        }
        /// <summary>
        /// 创建抽检单
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static SimpleResult CreateCheckOrder(CreateCheckOrderInfo model) {
            var db = DbHelper.GetDbClient();
            try {
                // 绑定操作:插入出库单、所有的出库单明细
                using (var tran = db.Ado.UseTran()) {
                var order = new TN_Check_Order {
                    S_CG_ID = model.CgId,
                    S_ITEM_NAME = model.ItemName,
                    S_BATCH_NO = model.BatchNo,
                    N_QTY = model.Qty,
                    S_END_AREA = model.EndArea,
                };
                    var order = new TN_Check_Order {
                        S_NO = model.No,
                        S_CG_ID = model.CgId,
                        S_ITEM_NAME = model.ItemName,
                        S_BATCH_NO = model.BatchNo,
                        N_COUNT = model.N_QTY,
                        S_END_AREA = model.EndArea,
                    };
                if (db.Insertable<TN_Check_Order>(order).ExecuteCommand() > 0) {
                    return BuildSimpleResult(0, "插入抽检单成功:" + JsonConvert.SerializeObject(order));
                    if (db.Insertable<TN_Check_Order>(order).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(2, "生成 抽检单 失败:" + JsonConvert.SerializeObject(order));
                    }
                    for (int i = 0; i < model.N_QTY; i++) {
                        var detail = new TN_Check_Detail {
                            S_NO = model.No,
                            S_CG_ID = model.CgId,
                            S_BATCH_NO = model.BatchNo,
                            S_END_AREA = model.EndArea
                        };
                        if (db.Insertable<TN_Check_Detail>(detail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return BuildSimpleResult(3, "生成 抽检单明细 失败:" + JsonConvert.SerializeObject(detail));
                        }
                    }
                    tran.CommitTran();
                }
                else {
                    return BuildSimpleResult(2, "插入抽检单失败:" + JsonConvert.SerializeObject(order));
                }
                return BuildSimpleResult(0, $"创建 抽检单 成功:单号 {model.No}");
            }
            catch (Exception ex) {
                return BuildSimpleEx(ex);
            }
        }
        public static SimpleResult QualifiedBack(QualifiedBackInfo model) {
            var db = DbHelper.GetDbClient();
            try {
                var cgDetail = db.Queryable<TN_CG_Detail>()
                    .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode)
                    .First();
                if (cgDetail == null) {
                    return BuildSimpleResult(2, "没有找到待回库的抽检物料");
                }
                cgDetail.N_ITEM_STATE = 0;
                cgDetail.S_ITEM_STATE = "合格";
                // TODO 不需要联立三个表
                var startLocCntrRel = db.Queryable<TN_Location, TN_Loc_Container>
                    ((l, c) => l.S_CODE == c.S_LOC_CODE)
                    .Where(ExprHelper.LocIsFree)
                    .Select((l, c) => c)
                    .First();
                if (startLocCntrRel == null) {
                    return BuildSimpleResult(0, "没有找到合适的起点货位");
                }
                var endLoc = db.Queryable<TN_Location>()
                    .Where(ExprHelper.LocBelongsToArea(startLocCntrRel.S_CNTR_TYPE == "托盘" ? AreaName.满托存放区 :
                        startLocCntrRel.S_CNTR_TYPE == "好运箱" ? AreaName.满箱存放区 : ""))
                    .Where(ExprHelper.LocIsFree)
                    .Where(ExprHelper.LocIsEmpty).First();
                if (endLoc == null) {
                    return BuildSimpleResult(3, "查询:没有找到合适的终点货位");
                }
                using (var tran = db.Ado.UseTran()) {
                    if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it =>
                        new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(4, "修改物料状态为合格 失败");
                    }
                    if (!TaskHelper.LogCreateTask(startLocCntrRel.S_LOC_CODE, startLocCntrRel.S_CNTR_CODE,
                        endLoc.S_CODE, TaskName.抽检_合格回库)) {
                        tran.RollbackTran();
                        return BuildSimpleResult(5, "创建任务失败", false);
                    }
                    tran.CommitTran();
                }
                return BuildSimpleResult(0, "物料合格回库任务创建成功");
            }
            catch (Exception ex) {
                return BuildSimpleEx(ex);
            }
        }
        public static SimpleResult UnqualifiedShift(UnqualifiedShiftInfo model) {
            var db = DbHelper.GetDbClient();
            try {
                var cgDetail = db.Queryable<TN_CG_Detail>()
                    .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode)
                    .First();
                if (cgDetail == null) {
                    return BuildSimpleResult(2, "没有找到待回库的抽检物料");
                }
                cgDetail.N_ITEM_STATE = 2;
                cgDetail.S_ITEM_STATE = "不合格";
                // TODO 不需要联立三个表
                var startLocCntrRel = db.Queryable<TN_Location, TN_Loc_Container>
                    ((l, c) => l.S_CODE == c.S_LOC_CODE)
                    .Where(ExprHelper.LocIsFree)
                    .Select((l, c) => c)
                    .First();
                if (startLocCntrRel == null) {
                    return BuildSimpleResult(0, "没有找到合适的起点货位");
                }
                var endLoc = db.Queryable<TN_Location>()
                    .Where(l => l.S_AREA_CODE == model.EndArea)
                    .Where(ExprHelper.LocIsFree)
                    .Where(ExprHelper.LocIsEmpty).First();
                if (endLoc == null) {
                    return BuildSimpleResult(3, "查询:没有找到合适的终点货位");
                }
                using (var tran = db.Ado.UseTran()) {
                    if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it =>
                        new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(4, "修改物料状态为合格 失败");
                    }
                    if (!TaskHelper.LogCreateTask(startLocCntrRel.S_LOC_CODE, startLocCntrRel.S_CNTR_CODE,
                        endLoc.S_CODE, TaskName.抽检_不合格移库)) {
                        tran.RollbackTran();
                        return BuildSimpleResult(5, "创建任务失败", false);
                    }
                    tran.CommitTran();
                }
                return BuildSimpleResult(0, "物料不合格移库任务创建成功");
            }
            catch (Exception ex) {
                return BuildSimpleEx(ex);
            }
        }
        #endregion
        #region Mobox 功能
@@ -419,40 +562,49 @@
        /// <returns></returns>
        public static SimpleResult FinishedOutbound(FinishedOutboundInfo model) {
            var db = DbHelper.GetDbClient();
            var orderNo = GenerateOrderNo("出库单号", "ON");
            try {
                if (string.IsNullOrEmpty(model.No)) {
                if (string.IsNullOrEmpty(orderNo)) {
                    return BuildSimpleResult(2, "出库单号不能为空");
                }
                if (model.OutboundDetails.Count == 0) {
                    return BuildSimpleResult(2, "出库单明细没有项目");
                }
                using (var tran = db.Ado.UseTran()) {
                    var cgDetailList = SelectCgByTotalQty(model);
                    if (cgDetailList.Count == 0) {
                        return BuildSimpleResult(3, "没有合适的物料可以出库");
                    }
                    // NOTE 如果创建order的时候就指定具体出库物料的cntr,那么如果在创建任务前,这个物料被错误抽检了怎么办
                    foreach (var cgDetail in cgDetailList) {
                        var detail = new TN_Outbound_Detail {
                            S_NO = orderNo,
                            S_ITEM_CODE = cgDetail.S_ITEM_CODE,
                            S_BATCH_NO = cgDetail.S_BATCH_NO,
                            S_CNTR_CODE = cgDetail.S_CNTR_CODE,
                            S_END_AREA = model.EndArea
                        };
                        if (db.Insertable<TN_Outbound_Detail>(detail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return BuildSimpleResult(4, "生成出库单明细失败:" + JsonConvert.SerializeObject(detail));
                        }
                    }
                    var order = new TN_Outbound_Order {
                        S_NO = model.No,
                        N_FORCE = model.Forced ? 1 : 0
                        S_NO = orderNo,
                        S_ITEM_CODE = model.ItemCode,
                        S_BATCH_NO = model.BatchNo,
                        F_QTY = model.Qty,
                        F_OUT_QTY = cgDetailList.Sum(a => a.F_QTY),
                        S_END_AREA = model.EndArea
                    };
                    if (db.Insertable<TN_Outbound_Order>(order).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(3, "生成出库单失败:" + JsonConvert.SerializeObject(order));
                    }
                    foreach (var detail in model.OutboundDetails) {
                        var newDetail = new TN_Outbound_Detail {
                            S_NO = order.S_NO,
                            S_CG_ID = detail.CgCode,
                            S_BATCH_NO = detail.PatchNo,
                            N_QTY = detail.Qty,
                            N_FORCE = order.N_FORCE,
                            S_END_AREA = detail.EndArea
                        };
                        if (db.Insertable<TN_Outbound_Detail>(newDetail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return BuildSimpleResult(4, "生成出库单明细失败:" + JsonConvert.SerializeObject(detail));
                        }
                        return BuildSimpleResult(5, "生成出库单失败:" + JsonConvert.SerializeObject(order));
                    }
                    tran.CommitTran();
@@ -471,36 +623,52 @@
        /// <returns></returns>
        public static SimpleResult FinishedOutboundForce(FinishedOutboundInfo model) {
            var db = DbHelper.GetDbClient();
            var orderNo = GenerateOrderNo("出库单号", "ON");
            try {
                if (string.IsNullOrEmpty(model.No)) {
                if (string.IsNullOrEmpty(orderNo)) {
                    return BuildSimpleResult(2, "出库单号不能为空");
                }
                using (var tran = db.Ado.UseTran()) {
                    var order = new TN_Outbound_Order {
                        S_NO = model.No,
                        N_FORCE = model.Forced ? 1 : 0
                    };
                    if (db.Insertable<TN_Outbound_Order>(order).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(3, "生成出库单失败:" + JsonConvert.SerializeObject(order));
                    var cgDetailList = SelectCgByTotalQty(model);
                    if (cgDetailList.Count == 0) {
                        return BuildSimpleResult(3, "没有合适的物料可以出库");
                    }
                    foreach (var detail in model.OutboundDetails) {
                        var newDetail = new TN_Outbound_Detail {
                            S_NO = order.S_NO,
                            S_CG_ID = detail.CgCode,
                            S_BATCH_NO = detail.PatchNo,
                            N_QTY = detail.Qty,
                            N_FORCE = order.N_FORCE
                    // NOTE 如果创建order的时候就指定具体出库物料的cntr,那么如果在创建任务前,这个物料被错误抽检了怎么办
                    foreach (var cgDetail in cgDetailList) {
                        var detail = new TN_Outbound_Detail {
                            S_NO = orderNo,
                            S_ITEM_CODE = cgDetail.S_ITEM_CODE,
                            S_BATCH_NO = cgDetail.S_BATCH_NO,
                            S_CNTR_CODE = cgDetail.S_CNTR_CODE,
                            S_END_AREA = model.EndArea
                        };
                        if (db.Insertable<TN_Inbound_Order>(order).ExecuteCommand() <= 0) {
                        if (db.Insertable<TN_Outbound_Detail>(detail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return BuildSimpleResult(4, "生成出库单明细失败:" + JsonConvert.SerializeObject(detail));
                        }
                    }
                    var order = new TN_Outbound_Order {
                        S_NO = orderNo,
                        S_ITEM_CODE = model.ItemCode,
                        S_BATCH_NO = model.BatchNo,
                        F_QTY = model.Qty,
                        F_OUT_QTY = cgDetailList.Sum(a => a.F_QTY),
                        S_END_AREA = model.EndArea
                    };
                    if (db.Insertable<TN_Outbound_Order>(order).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return BuildSimpleResult(5, "生成出库单失败:" + JsonConvert.SerializeObject(order));
                    }
                    tran.CommitTran();
                }
                return BuildSimpleResult(0, "生成出库单成功");
@@ -510,6 +678,63 @@
            }
        }
        public static List<TN_CG_Detail> SelectCgByTotalQty(FinishedOutboundInfo model) {
            var db = DbHelper.GetDbClient();
            var result = new List<TN_CG_Detail>();
            var targetNum = model.Qty;
            try {
                var targetCg = db.Queryable<TN_CG_Detail>().Where(a => a.S_ITEM_CODE == model.ItemCode
                && a.F_QTY > targetNum).
                OrderBy(a => a.F_QTY, OrderByType.Asc).First();
                if (targetCg != null) //刚好有一行满足条件
                {
                    result.Add(targetCg);
                    return result;
                }
                // NOTE 根据总量选detail时,是否需要考虑货位的高低?
                var sortedMaterials = db.Queryable<TN_CG_Detail, TN_Loc_Container>((d, c) => d.S_CNTR_CODE == c.S_CNTR_CODE)
                    .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_BATCH_NO == model.BatchNo && d.F_QTY > 0)
                    .Where((d, c) => c.S_CNTR_TYPE == model.CntrType)
                    .Where(d => (model.ForcedOut && d.N_ITEM_STATE == 0 && d.S_ITEM_STATE == "合格")
                        || (!model.ForcedOut && (d.N_ITEM_STATE == 0 && d.S_ITEM_STATE == "合格"
                        || d.N_ITEM_STATE == 1 && d.S_ITEM_STATE == "待检")))
                    .OrderBy(d => d.F_QTY, OrderByType.Desc)
                    .OrderBy(d => d.N_ITEM_STATE, OrderByType.Asc).ToList();
                if (sortedMaterials.Count == 0)//没有满足条件的
                {
                    return result;
                }
                float countNum = 0;
                foreach (var mat in sortedMaterials) {
                    countNum += mat.F_QTY;
                    result.Add(mat);
                    if (countNum >= targetNum) {
                        break;
                    }
                }
                if (result.Sum(a => a.F_QTY) >= targetNum) {
                    return result;
                }
                else {
                    result.Clear();
                    return result;
                }
            }
            catch (Exception ex) {
                throw ex;
            }
        }
        private static string GenerateOrderNo(string snType, string prefix) {
            var id = SysHelper.GetSerialNumber(snType, prefix);
            var date = DateTime.Now.ToString("yyMMdd");
            return $"ON{date}{id.ToString().PadLeft(4, '0')}";
        }
        #endregion
    }