schangxiang@126.com
2025-09-17 ff43ddf18764629ff875478e4e47a7281cbd230a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
using Admin.NET.Application.CommonHelper;
using Admin.NET.Application.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Admin.NET.Application;
 
/// <summary>
/// 下架服务
/// </summary>
[ApiDescriptionSettings(ApplicationConst.WmsOperationsGroupName, Order = 100)]
public class WmsUnshelveService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<WmsBasePlace> _wmsPlaceRep;
    private readonly SqlSugarRepository<WmsBaseContainer> _wmsContainerRep;
    private readonly SqlSugarRepository<WmsContainerPlace> _wmsContainerPlaceRep;
    private readonly SqlSugarRepository<WmsStockQuan> _wmsStockQuanRep;
    private readonly SqlSugarRepository<WmsTask> _wmsTaskRep;
    private readonly SqlSugarRepository<WmsBaseContainerType> _wmsContainerTypeRep;
    private readonly SqlSugarRepository<WmsBaseContainerPackaging> _wmsContainerPackagingRep;
    private readonly SqlSugarRepository<v_wms_stock_quan> _v_wms_stock_quanRep;
    private readonly SqlSugarRepository<WmsOrderMovement> _wmsOrderMovementRep;
    private readonly SqlSugarRepository<WmsOrderMovementDetails> _wmsOrderMovementDetailsRep;
    private readonly SqlSugarRepository<WmsConfigSerialSN> _repSNRep;
    private readonly SqlSugarRepository<WmsConfigNoRule> _WmsNoCreateRuleRep;
    private readonly SqlSugarRepository<WmsLogAction> _wmsLogActionRep;
    private readonly SqlSugarRepository<WmsRecordTrans> _wmsRecordTransRep;
    private readonly SqlSugarRepository<WmsBaseBusinessType> _wmsBaseBusinessTypeRep;
    private readonly SqlSugarRepository<WmsBaseArea> _WmsAreaRep;
    /// <summary>
    /// 构造函数
    /// </summary>
    public WmsUnshelveService(SqlSugarRepository<WmsBasePlace> wmsPlaceRep, 
                              SqlSugarRepository<WmsBaseContainer> wmsContainerRep, 
                              SqlSugarRepository<WmsContainerPlace> wmsContainerPlaceRep, 
                              SqlSugarRepository<WmsStockQuan> wmsStockQuanRep,
                              SqlSugarRepository<WmsTask> wmsTaskRep,
                              SqlSugarRepository<WmsBaseContainerType> wmsContainerTypeRep,
                              SqlSugarRepository<WmsBaseContainerPackaging> wmsContainerPackagingRep,
                              SqlSugarRepository<v_wms_stock_quan> v_wms_stock_quanRep,
                              SqlSugarRepository<WmsOrderMovement> wmsOrderMovementRep,
                              SqlSugarRepository<WmsOrderMovementDetails> wmsOrderMovementDetailsRep,
                              SqlSugarRepository<WmsConfigSerialSN> repSNRep,
                              SqlSugarRepository<WmsConfigNoRule> wmsNoCreateRuleRep,
                              SqlSugarRepository<WmsLogAction> wmsLogActionRep,
                              SqlSugarRepository<WmsRecordTrans> wmsRecordTransRep,
                              SqlSugarRepository<WmsBaseBusinessType> wmsBaseBusinessTypeRep,
                              SqlSugarRepository<WmsBaseArea> wmsAreaRep)
    { 
        this._wmsPlaceRep = wmsPlaceRep;
        this._wmsContainerRep = wmsContainerRep;
        this._wmsContainerPlaceRep = wmsContainerPlaceRep;
        this._wmsStockQuanRep = wmsStockQuanRep;
        this._wmsTaskRep = wmsTaskRep;
        this._wmsContainerTypeRep= wmsContainerTypeRep;
        this._wmsContainerPackagingRep= wmsContainerPackagingRep;
        this._v_wms_stock_quanRep = v_wms_stock_quanRep;
        this._wmsOrderMovementRep= wmsOrderMovementRep;
        this._wmsOrderMovementDetailsRep=wmsOrderMovementDetailsRep;
        this._repSNRep= repSNRep;
        this._WmsNoCreateRuleRep = wmsNoCreateRuleRep;
        this._wmsLogActionRep = wmsLogActionRep;
        this._wmsRecordTransRep = wmsRecordTransRep;
        this._wmsBaseBusinessTypeRep = wmsBaseBusinessTypeRep;
        this._WmsAreaRep = wmsAreaRep;
    }
 
    /// <summary>
    /// PDA容器下架判断目标库位是否异常
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "GetPlaceInfo", Description = "PDA容器下架判断目标库位是否异常")]
    [Description("/Unshelve/GetPlaceInfo")]
    public async Task GetPlaceInfo(GetPlaceInfoInput input)
    {
        var wmsPlace = await _wmsPlaceRep.GetFirstAsync(o => o.PlaceCode == input.PlaceCode && o.IsDelete==false);
        if(wmsPlace==null) throw Oops.Oh($"该地标/库位不存在,请检查库位基础数据!");
        if (wmsPlace.PlaceStatus == PlaceStatusEnum.锁定)
        {
            var wmsTask = await _wmsTaskRep.GetFirstAsync(o => o.SourcePlaceCode == wmsPlace.PlaceCode&&o.TaskStatus== TaskStatusEnum.已下发);
            throw Oops.Oh($"该库位被任务号{wmsTask.TaskNo}锁定,不可使用!");
        }
        if(wmsPlace.PlaceStatus== PlaceStatusEnum.封存)   throw Oops.Oh($"该库位已冻结,不可使用!如需解冻,请先解冻该库位!");
    }
 
    /// <summary>
    /// PDA下架查询-获取物料编号对应的容器类型
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "GetMaterialCodeByInfo", Description = "PDA容器下架查询-获取物料编号对应的容器类型")]
    [Description("/Unshelve/GetMaterialCodeByInfo")]
    public async Task<GetContainerTypeOutPut> GetMaterialCodeByInfo([FromQuery] GetMaterialCodeByInfoInput input)
    { 
        if(string.IsNullOrEmpty(input.MaterialCode)) throw Oops.Oh($"物料编号不能为空!!");
        var wmsMaterial = await _wmsContainerPackagingRep.AsQueryable().
                            WhereIF(!string.IsNullOrEmpty(input.MaterialCode), o => o.MaterialCode.Contains(input.MaterialCode.Trim())).FirstAsync();
        if (wmsMaterial == null) throw Oops.Oh($"该物料编号{input.MaterialCode}在系统中没有关联容器类型,请先添加容器类型!");
        var wmsContainerType = new GetContainerTypeOutPut()
        {
            ContainerTypeCode = wmsMaterial.ContainerTypeCode,
            ContainerTypeName = wmsMaterial.ContainerTypeName,
        };
        return wmsContainerType;
    }
 
    /// <summary>
    /// 容器下架执行
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "ContainerUnshelveExecute", Description = "PDA容器下架确认-创建下架单、调度任务")]
    [Description("/Unshelve/ContainerUnshelveExecute")]
    public async Task ContainerUnshelveExecute(WmsUnshelveInput input)
    {
        //ly-0813 添加来源库区
        //var AreaCodeItem = await _WmsAreaRep.GetFirstAsync(w => w.AreaCode == input.AreaCode && w.IsDelete == false);
        //if (AreaCodeItem==null)
        //{
        //    throw Oops.Oh($"来源库区{input.AreaCode}不存在!");
        //}
 
        //获取库存中已上架的容器类型集合按时间排序 排除目标库位是自己的
        var contaierList = await _v_wms_stock_quanRep.AsQueryable()
                                .Where(o => o.PlaceCode != input.PlaceCode &&  o.ContainerTypeCode == input.ContainerTypeCode && o.MaterialTypeCode=="RQ" && o.IsDelete == false && o.StockStatus==StockStatusEnum.已上架)
                                .OrderBy(o=>o.CreateTime).ToListAsync();
        //判断当前容器类型是否有库存
        if (contaierList.Count<=0) throw Oops.Oh($"当前容器类型{input.ContainerTypeCode}没有库存,请先上架该类型的容器!");
        //查询第一个容器号的容器组盘集合  不能自己呼叫自己
        var contaierInfoList = contaierList
            .Where(u => u.ContainerCode == contaierList[0].ContainerCode && u.ContainerCode != input.PlaceCode)
            .ToList();
        //if (contaierInfoList.Count <= 0)
        //{
        //    throw Oops.Oh($"来源库区{input.AreaCode}没有找到已上架的容器!");
        //}
 
        //源库位
        string sourcePlaceCode = contaierInfoList[0].PlaceCode;
        string sourcePlaceName = contaierInfoList[0].PlaceName;
 
        //if (contaierInfoList[0].PlaceCode == input.PlaceCode)
        //{
        //    throw Oops.Oh($"来源库位{contaierInfoList[0].PlaceCode}和目标库位{input.PlaceCode}相同!");
        //}
 
        //新增事务记录
        List<WmsRecordTrans> addWmsRecordTransList = new List<WmsRecordTrans>();
        //新增操作履历
        List<WmsLogAction> addWmsLogActionList = new List<WmsLogAction>();
        //新增下架单明细
        List<WmsOrderMovementDetails> addWmsOrderMovementDetailsList = new List<WmsOrderMovementDetails>();
 
        //获取目标库位信息
        WmsBasePlace toPlace = null;
        if (!string.IsNullOrWhiteSpace(input.PlaceCode))
        {
            toPlace = await _wmsPlaceRep.GetFirstAsync(w => w.PlaceCode == input.PlaceCode && w.IsDelete == false);
            if (toPlace == null)
            {
                throw Oops.Oh($"目标库位{input.PlaceCode}不存在!");
            }
            if (toPlace.IsDisabled == true)
            {
                throw Oops.Oh($"目标库位{input.PlaceCode}已禁用!");
            }
            if (toPlace.IsVirtually == true)
            {
                throw Oops.Oh($"目标库位{input.PlaceCode}是虚拟库位!");
            }
            //库位属性 正常和禁出的可以组盘上架
            if (toPlace.PlaceStatus != PlaceStatusEnum.正常 && toPlace.PlaceStatus != PlaceStatusEnum.禁出)
            {
                throw Oops.Oh($"目标库位{input.PlaceCode}库位属性是{toPlace.PlaceStatus.GetDescription()}!");
            }
        }
        else
        {
            //用户必须指定一个 库位。
            throw Oops.Oh($"目标库位不能为空!");
        }
        BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.容器下架;
        //    获取业务类型 update by liuwq 2024 07 30
        var wmsBaseBusinessType = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _wmsBaseBusinessTypeRep);
 
        int lineNumber = 0;//移动单明细行号
        var hearId = Yitter.IdGenerator.YitIdHelper.NextId();//上架单ID
        //3.循环库存信息-创建上架单明细
        foreach (var vstockQuan in contaierInfoList)
        {
            var wmsContainerItem = await _wmsContainerRep.GetFirstAsync(w => w.ContainerCode == vstockQuan.SNCode &&w.IsDelete == false);
            if (wmsContainerItem == null) throw Oops.Oh($"容器{vstockQuan.SNCode}不存在!");
            if (wmsContainerItem.IsDisabled == true) throw Oops.Oh($"容器{vstockQuan.SNCode}已禁用!");
            if (wmsContainerItem.IsVirtually == true) throw Oops.Oh($"容器{vstockQuan.SNCode}是虚拟容器!");
            var stockQuan = await _wmsStockQuanRep.GetFirstAsync(w => w.Id==vstockQuan.Id);
            if(stockQuan==null) throw Oops.Oh($"容器{vstockQuan.SNCode}不存在!");
 
            if (string.IsNullOrWhiteSpace(vstockQuan.ContainerCode))
            {
                throw Oops.Oh($"库存{vstockQuan.SNCode}容器号不能为空!");
            }
            lineNumber++;
            #region 创建下架单明细
            //3.根据容器的库存创建下架单明细
            var wmsOrderMovementDetails = new WmsOrderMovementDetails()
            {
                MovementId = hearId,
                LineNumber = OrderHelper.AutoCompleEBELP(lineNumber.ToString(), 4),//lineNumber.ToString(),
                SNCode = vstockQuan.SNCode,
                SupplierCode = vstockQuan.SupplierCode,
                SupplierName = vstockQuan.SupplierName,
                Batch = vstockQuan.Batch,
                ErpOrderNo = vstockQuan.ErpOrderNo,
                ErpCode = vstockQuan.ErpCode,
                Unit = vstockQuan.MaterialUnit,
                SupplierBatch = vstockQuan.SupplierBatch,
                OrderStatus = OrderStatusEnum.新建,
                OrderStatusName = OrderStatusEnum.新建.GetDescription(),
                //ToAreaCode = input.ToAreaCode,
                //ToPlaceCode = input.ToPlaceCode,
                ContainerCode = vstockQuan.ContainerCode,
                ContainerName = vstockQuan.ContainerName,
                SourceWarehouseCode = vstockQuan.WarehouseCode,
                SourceWarehouseName = vstockQuan.WarehouseName,
                SourceAreaCode = vstockQuan.AreaCode,
                SourceAreaName = vstockQuan.AreaName,
                SourcePlaceCode = vstockQuan.PlaceCode,
                SourcePlaceName = vstockQuan.PlaceName,
                ToPlaceCode = toPlace.PlaceCode,
                ToPlaceName = toPlace.PlaceName,
                ToAreaCode = toPlace.AreaCode,
                ToAreaName = toPlace.AreaName,
                MaterialCode = vstockQuan.MaterialCode,
                MaterialName = vstockQuan.MaterialName,
                Quantity = vstockQuan.Quantity,
                ActionRemark = "PDA下架架创建下架单",
                ActionTime = DateTime.Now
            };
            addWmsOrderMovementDetailsList.Add(wmsOrderMovementDetails);
            #endregion
            #region  转移库存操作日志
            string recordTransRemarks = string.Empty;
           
          
 
            //新增操作日志
            WmsLogAction wareActionLog =  LogActionHelper.CreateWmsLogAction(vstockQuan.Id, businessTypeEnum.GetDescription(), recordTransRemarks);
            addWmsLogActionList.Add(wareActionLog);
            #endregion
        }
 
        // 获取当前时间
        DateTime currentTime = DateTime.Now;
        // 格式化为年月日字符串
        string formattedDate = currentTime.ToString("yyyyMMdd");
        //按照单号规则生成单号 - 查找最新的创建的一条单据记录
        var newestOrder = await _wmsOrderMovementRep.AsQueryable().Where(p => p.OrderType == OrderTypeEnum.下架单).Where(p => p.OrderNo.Contains(formattedDate)).OrderBy(it => it.CreateTime, OrderByType.Desc)
                             .FirstAsync();
 
 
        //按照单号规则生成单号-ly
        var OrderNoSjd = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.下架单, _WmsNoCreateRuleRep, _repSNRep, (int)businessTypeEnum, newestOrder == null ? null : newestOrder.OrderNo);
        if (OrderNoSjd == null || OrderNoSjd == "")
        {
            var OrderNoSjdRQ = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.下架单, _WmsNoCreateRuleRep, _repSNRep, (int)businessTypeEnum, newestOrder == null ? null : newestOrder.OrderNo);
            if (OrderNoSjdRQ != null || OrderNoSjdRQ != "")
            {
                OrderNoSjd = OrderNoSjdRQ;
            }
            else
            {
                OrderNoSjd = Yitter.IdGenerator.YitIdHelper.NextId().ToString();
            }
        }
 
        var businessTypeInfo = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _wmsBaseBusinessTypeRep);
 
        //4 创建下架单
        var addWmsOrderMovement = new WmsOrderMovement()
        {
            Id = hearId,
            OrderNo = OrderNoSjd, //按照单号规则生成单号-ly
            OrderType = OrderTypeEnum.下架单,
            OrderTypeName = OrderTypeEnum.下架单.GetDescription(),
            BusinessType = (int)businessTypeEnum,
            BusinessTypeName = businessTypeEnum.GetDescription(),
            OrderStatus = OrderStatusEnum.新建,
            OrderStatusName = OrderStatusEnum.新建.GetDescription(),
            OrderSocure = SourceByEnum.系统
        };
        BusinessTypeEnum wmsTaskBusinessTypeEnum = BusinessTypeEnum.容器下架;
        //5.创建调度任务
        var wmsTask = new WmsTask()
        {
            MoveType = businessTypeInfo.MoveType,
            MoveTypeName = businessTypeInfo.MoveTypeName,
            BusinessType = businessTypeInfo.BusinessTypeValue,
            BusinessTypeName = businessTypeInfo.BusinessTypeName,
            ContainerCode = contaierList.FirstOrDefault().ContainerCode,
            IsFlagFinish = false,
            OrderNo = addWmsOrderMovement.OrderNo,
            TaskDescribe = "PDA容器下架",
            TaskStatus = TaskStatusEnum.新建,
            TaskStatusName = TaskStatusEnum.新建.GetDescription(),
            TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(),
            TaskPriority = 0,
            TaskName = wmsTaskBusinessTypeEnum.GetDescription(),
            ToAreaCode = toPlace.AreaCode,
            SourcePlaceCode = sourcePlaceCode,    
            ToPlaceCode = input.PlaceCode
        };
      
        var _tenant = _wmsOrderMovementRep.AsTenant();
        try
        {
            await _tenant.BeginTranAsync();
            #region 事务内执行操作
 
            //新增操作日志
            await _wmsLogActionRep.InsertRangeAsync(addWmsLogActionList);
 
            if (addWmsOrderMovementDetailsList?.Count > 0)
            {
                //新增下架单
                await _wmsOrderMovementRep.InsertAsync(addWmsOrderMovement);
                await _wmsOrderMovementDetailsRep.InsertRangeAsync(addWmsOrderMovementDetailsList);
 
 
                //新增任务调度
                await _wmsTaskRep.InsertAsync(wmsTask);
            }
            else
            {
                throw Oops.Oh($"下架单明细为空!");
            }
            #endregion
            await _tenant.CommitTranAsync();
        }
        catch
        {
            await _tenant.RollbackTranAsync();
            throw;
        }
    }
 
}