服务端的TigerApi 框架,基于.NET6 2024 版本
Rodney Chen
2025-04-02 eb29ee75c7f2f4154b7a3d0c475f94e0b964e996
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
using Rhea.Common;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tiger.Model;
using Tiger.IBusiness;
using Tiger.Model.Entitys.MES.Position;
 
namespace Tiger.Business.WMS.Transaction
{
    /// <summary>
    /// 标准下架事务
    /// </summary>
    public class Out_Default : WmsTask, IOut_Default
    {
        public IOut_Default Init(string id, string userCode, string apiHost, string orgCode)
        {
            base.Init(id, userCode, apiHost, orgCode);
            Logger.Console.Info($"Start {this.GetType().Name} Transaction[ID: {TransID}]");
            return this;
        }
 
        #region Propertys & Variables
 
        #endregion
 
        #region Functions
        /// <summary>
        /// 扫描入口
        /// </summary>
        public async Task<ApiAction<ScanOutput>> Scan(BaseInput input)
        {
            var action = new ApiAction<ScanOutput>(new ScanOutput());
            try
            {
                if (input.SN.IsNullOrEmpty())
                {
                    action.IsSuccessed = false;
                    //action.LocaleMsg = Biz.L("条码不能为空");
                    action.LocaleMsg = Biz.L("WMS.Default.ScanItem.SnEmptyFailure");
                    return SetOutPutMqttMsg(action, input.Locale);
                }
                //扫描物料并复核
                {
                    action = await ScanItem(input);
                }
            }
            catch (Exception ex)
            {
                //取消当前操作
                ResetTrans();
                //action.CatchExceptionWithLog(ex, $"扫描[{input.SN}]异常");
                action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.Scan.ScanException", input.SN));
            }
            return SetOutPutMqttMsg(action, input.Locale);
        }
 
        /// <summary>
        /// 扫描物料并复核,如果是智能货架则亮灯提醒储位
        /// </summary>
        public async Task<ApiAction<ScanOutput>> ScanItem(BaseInput input)
        {
            var action = new ApiAction<ScanOutput>(new ScanOutput() { Command = Command });
            try
            {
                if (CurInvItem.IsNullOrEmpty())
                {
                    //解析条码
                    Result<IInventory> result = GetInventory(input.SN, input.AuthOption, true);
                    if (!result.IsSuccessed)
                    {
                        action.IsSuccessed = false;
                        action.LocaleMsg = result.LocaleMsg;
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    var inv = result.Data as Inventory;
 
                    //验证条码是否正确
                    if (!inv.isNormalStatus || inv.Status != WMS_ITEM.STATUSs.InStore)
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = Biz.L($"状态[{0}]异常,请重新扫描");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.StatusException", string.Join(',', inv.StatusList.Select(x => x.GetDesc())));
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    //储位验证
                    if (inv.Location.IsNullOrEmpty())
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = Biz.L($"条码[{0}]库存信息异常: 没有储位信息,请先上架后再扫描(储位Id: {1})");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.LocationIsNull", inv.CurPkg.SN, inv.CurPkg.LOCATION_ID);
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    //物料验证
                    if (inv.ItemInfo.IsNullOrEmpty() || inv.ItemInfo.IS_ACTIVE == "N")
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = Biz.L($"物料编码[{0}]不存在或者该物料未启用");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ItemCodeNotExistsOrNotActive", inv.ItemInfo.ITEM_CODE.IsNullOrEmpty(inv.Barcode.ItemCode));
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    CurInvItem = inv;
 
                    //把物料数量返回前端确认要下架的数量
                    if (CurInvItem.Items.Any(q => q.QTY > 1))
                    {
                        action.Data.Data = CurInvItem.Items.Select(q => new { q.SN, q.QTY });
                        action.Data.Command = Command = "ComfirmQty";
                        //action.LocaleMsg = Biz.L("请确认条码[{0}]要下架的数量");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ComfirmOutQty", input.SN);
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                }
 
                Dictionary<string, double> downDic = null;
                //更新下架后的物料数量
                if (Command == "ComfirmQty")
                {
                    var qtyList = (input.Data ?? "").JsonToObject<List<WMS_ITEM>>() ?? new List<WMS_ITEM>();
                    if (!qtyList.Any() || qtyList.Sum(q => q.QTY) <= 0)
                    {
                        action.IsSuccessed = false;
                        action.Data.Data = CurInvItem.Items.Select(q => new { q.SN, q.QTY });
                        action.Data.Command = Command = "ComfirmQty";
                        //action.LocaleMsg = Biz.L("下架数量不能小于等于零,请重新确认条码[{0}]的下架数量");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ReComfirmOutQty", input.SN);
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    else if (qtyList.Any(q => q.QTY > CurInvItem.Items.First(i => i.SN == q.SN).QTY))
                    {
                        action.IsSuccessed = false;
                        action.Data.Data = CurInvItem.Items.Select(q => new { q.SN, q.QTY });
                        action.Data.Command = Command = "ComfirmQty";
                        //action.LocaleMsg = Biz.L("下架数量不能超过原条码数量,请重新确认条码[{0}]的下架数量");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanItem.ReComfirmExceedOutQty", input.SN);
                        return SetOutPutMqttMsg(action, input.Locale);
                    }
                    else
                    {
                        downDic = qtyList.ToDictionary(k => k.SN, v => v.QTY);
                        Command = "Normal";
                    }
                }
 
                //出库下架
                foreach (var item in CurInvItem.Items)
                {
                    item.TRANS_CODE = "Out_Default";
                    item.TRANS_NO = $"Out_Default_{DateTime.Now:yyyyMMdd}";
                }
                foreach (var item in CurInvItem.Packages)
                {
                    item.TRANS_CODE = "Out_Default";
                    item.TRANS_NO = $"Out_Default_{DateTime.Now:yyyyMMdd}";
                }
                Result downResult = TakeDown(downDic, input.AuthOption, WMS_ITEM.STATUSs.OffShelf);
                if (!downResult.IsSuccessed)
                {
                    action.IsSuccessed = false;
                    action.LocaleMsg = downResult.LocaleMsg;
                    ResetTrans();
                    return SetOutPutMqttMsg(action, input.Locale);
                }
 
                //灭灯
                if (CurInvItem.Shelf.IsLightShelf)
                {
                    await Share.Shelf.DownSingle(TransID, CurInvItem.Location);
                }
 
                //完成所有处理后使用事务保存数据
                action = DoIfFinish(action, input.Locale);
            }
            catch (Exception ex)
            {
                ResetTrans();
                //action.CatchExceptionWithLog(ex, $"扫描条码[{input.SN}]复核异常");
                action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.ScanItem.ScanException", input.SN));
            }
            return SetOutPutMqttMsg(action, input.Locale);
        }
 
        /// <summary>
        /// 扫描货架或者储位(供亮灯货架使用)
        /// </summary>
        public async Task<ApiAction<ScanOutput>> ScanShelf(string Code)
        {
            var action = new ApiAction<ScanOutput>(new ScanOutput() { Command = Command });
            try
            {
                if (Code.IsNullOrEmpty())
                {
                    action.IsSuccessed = false;
                    //action.LocaleMsg = Biz.L("请输入或扫描有效的货架/储位码");
                    action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ShelfCanNotEmpty");
                    return action;
                }
 
                CurScanShelf = new ScanShelfInfo();
 
                // 查询货架信息
                var whUnit = await MainDB.Queryable<V_WH_UNIT>().Where(t => t.SHELF_CODE.ToUpper() == Code.ToUpper() && t.AUTH_ORG == OrgCode).IncludesAllFirstLayer().FirstAsync();
 
                // 扫描货架代码,且为智能货架
                if (whUnit != null && whUnit.SHELF_TYPE == WMS_SHELF.SHELF_TYPEs.Smart.GetValue())
                {
                    CurScanShelf.Shelf = whUnit.Shelf;
                    CurScanShelf.WarehouseCode = whUnit.WH_CODE;
                    CurScanShelf.RegionCode = whUnit.REGION_CODE;
                    CurScanShelf.ShelfCode = whUnit.SHELF_CODE;
                    CurScanShelf.ShelfType = whUnit.SHELF_TYPE;
                    CurScanShelf.IsSmartRack = true;
                }
                // 扫描库位代码
                else
                {
                    var nLocation = await MainDB.Queryable<V_WH_UNIT>().Where(t => t.LOCATION_CODE.ToUpper() == Code.ToUpper() && t.AUTH_ORG == OrgCode).IncludesAllFirstLayer().FirstAsync();
                    if (nLocation == null)
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = Biz.L("储位[{0}]不存在");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.LocationNotExist", Code);
                        return action;
                    }
                    if (nLocation.IS_ACTIVE == "N")
                    {
                        action.IsSuccessed = false;
                        //action.LocaleMsg = Biz.L("扫描的储位[{0}]未启用");
                        action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ShelfOrLocationDisabled", Code);
                        return action;
                    }
                    //if (nLocation.Shelf.IsLightShelf || nLocation.Location.IS_SINGLE == "Y")
                    //{
                    //    var locationData = MainDB.Queryable<WMS_ITEM>().Where(q => q.LOCATION_ID == nLocation.LOCATION_ID && q.AUTH_ORG == OrgCode).First();
                    //    if (!locationData.IsNullOrEmpty())
                    //    {
                    //        action.IsSuccessed = false;
                    //        //action.LocaleMsg = Biz.L("储位[{0}]已存有物料[{1}],请检查系统库存信息");
                    //        action.LocaleMsg = Biz.L($"WMS.Default.ScanShelf.ItemAlreadyExistsInLocation", Code, locationData.SN);
                    //        return action;
                    //    }
                    //}
                    CurScanShelf.Shelf = nLocation.Shelf;
                    CurScanShelf.Location = nLocation.Location;
                    CurScanShelf.WarehouseCode = nLocation.WH_CODE;
                    CurScanShelf.RegionCode = nLocation.REGION_CODE;
                    CurScanShelf.ShelfCode = nLocation.SHELF_CODE;
                    CurScanShelf.LocationCode = nLocation.LOCATION_CODE;
                    CurScanShelf.IsSmartRack = false;
                }
 
                CurScanShelf.IsScanShelf = true;
                //action.LocaleMsg = Biz.L("扫描货架/储位[{0}]成功");
                action.LocaleMsg = Biz.L("WMS.Default.ScanShelf.ScanSucceeded", Code);
                action.Data.Data = CurScanShelf;
            }
            catch (Exception ex)
            {
                //取消当前操作
                ResetTrans();
                //action.CatchExceptionWithLog(ex, $"扫描货架/储位[{0}]异常");
                action.CatchExceptionWithLog(ex, Biz.L("WMS.Default.ScanShelf.ScanException", Code));
            }
            return action;
        }
 
        /// <summary>
        /// 完成所有处理后使用事务保存数据
        /// </summary>
        /// <param name="action"></param>
        /// <param name="locale"></param>
        /// <param name="doAfterSave"></param>
        /// <returns></returns>
        public ApiAction<ScanOutput> DoIfFinish(ApiAction<ScanOutput> action, string locale, Action doAfterSave = null)
        {
            //保存数据库
            SaveCommitListToDB();
 
            //保存数据成功后执行
            doAfterSave?.Invoke();
 
            // 返回数据
            action.Data.Data = new DefaultScanItemOutput()
            {
                SN = CurInvItem.SN,
                ItemCode = CurInvItem.ItemInfo.ITEM_CODE,
                MaterialName = CurInvItem.ItemInfo.ITEM_NAME,
                Qty = CurInvItem.CurPkg.QTY,
                Unit = CurInvItem.CurPkg.UNIT,
                regionCode = CurInvItem.Region.REGION_CODE,
                locationCode = CurInvItem.Location?.LOCATION_CODE,
                DateCode = CurInvItem.Items[0].PROD_DATE,
                ScanAfCut = CurInvItem.Warehouse.SCAN_AF_CUT
            };
 
            //action.LocaleMsg = Biz.L($"扫描条码[{0}]从储位[{1}]下架成功");
            action.LocaleMsg = Biz.L("WMS.Default.ScanItem.TakeDownSucceeded", CurInvItem.SN, CurInvItem.Location?.LOCATION_CODE);
 
            //重置工序
            ResetTrans();
            return SetOutPutMqttMsg(action, locale);
        }
 
        #endregion
 
        /// <summary>
        /// 重置事务数据,有需要则重写此方法
        /// </summary>
        public override void ResetTrans()
        {
            base.ResetTrans();
            Command = null;
            CurInvItem = null;
            CurScanShelf = null;
        }
 
        public override bool Close(bool needSaveHistoryLog = false)
        {
            this.IsFinished = true;
            return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished;
        }
 
    }//endClass
}