kyy
2025-09-04 2e37035392c187b26a09a2c2edcc6133e96532cc
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
using MES.Service.DB;
using MES.Service.Dto.webApi;
using MES.Service.Modes;
using MES.Service.util;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
 
namespace MES.Service.service;
 
/// <summary>
/// 收料单数据管理类(处理ERP收料单数据同步到MES收料单表)
/// 关联主表:MesInvItemArn,明细表:MesInvItemArnDetail
/// 关联ERP DTO:ErpSltz(聚合类)、ErpSltza(ERP主表)、ErpSltzBList(ERP明细)
/// </summary>
public class MesInvItemArnManager : Repository<MesInvItemArn>
{
    /// <summary>
    /// 批量保存收料单(主表+明细)- 事务保证批量操作一致性
    /// </summary>
    /// <param name="erpSltzList">ERP收料单列表(含主表+明细)</param>
    /// <returns>全部成功返回true,否则false</returns>
    public bool SaveList(List<ErpSltz> erpSltzList)
    {
        if (erpSltzList == null || !erpSltzList.Any())
            throw new ArgumentNullException(nameof(erpSltzList), "待保存的收料单列表不能为空");
 
        // 修复:用事务包裹批量操作,确保数据一致性
        return UseTransaction(db =>
        {
            foreach (var erpSltz in erpSltzList)
            {
                // 修复:调用事务内的Save方法,传入db实例
                if (!Save(db, erpSltz))
                {
                    return 0; // 单条失败,事务回滚
                }
            }
            return 1; // 全部成功
        }) > 0;
    }
 
    /// <summary>
    /// 单条保存收料单(主表+明细)- 事务内调用(修正访问修饰符,确保事务内可用)
    /// </summary>
    /// <param name="db">事务内的SqlSugar实例</param>
    /// <param name="erpSltz">ERP收料单(含主表+明细)</param>
    /// <returns>单条处理成功返回true</returns>
    private bool Save(SqlSugarScope db, ErpSltz erpSltz)
    {
        // 1. 参数校验
        if (erpSltz == null)
            throw new ArgumentNullException(nameof(erpSltz), "收料单数据不能为空");
        if (erpSltz.ErpSltza == null)
            throw new ArgumentNullException(nameof(erpSltz.ErpSltza), "收料单主表数据不能为空");
 
        // 2. 提取ERP主表和明细数据
        var erpMain = erpSltz.ErpSltza;
        var erpDetails = erpSltz.ErpSltzBList ?? new List<ErpSltzBList>();
 
        // 3. 修复:用事务内的db查询,确保数据一致性
        Guid mainId = GetOrCreateMainId(db, erpMain);
 
        // 4. 映射ERP数据到MES实体(修复字段注释,补充关键属性)
        var mesMain = MapErpSltzaToMesInvItemArn(erpMain, mainId);
        var mesDetails = MapErpSltzBListToMesInvItemArnDetail(erpDetails, mainId);
 
        // 5. 根据操作类型处理数据
        switch (erpMain.TYPE?.Trim())
        {
            case "1": // 新增
            case "2": // 更新
                return HandleSaveOrUpdate(db, mesMain, mesDetails, mainId);
            case "3": // 删除
                return HandleDelete(db, mesMain, mesDetails, mainId);
            default:
                throw new NotImplementedException($"未实现的收料单操作类型:{erpMain.TYPE}(支持类型:1-新增,2-更新,3-删除)");
        }
    }
 
    /// <summary>
    /// 单条保存收料单(主表+明细)- 对外公开接口(供控制器调用)
    /// </summary>
    /// <param name="erpSltz">ERP收料单数据(含主表+明细)</param>
    /// <returns>保存成功返回true</returns>
    public bool Save(ErpSltz erpSltz)
    {
        if (erpSltz == null)
            throw new ArgumentNullException(nameof(erpSltz), "收料单数据不能为空");
        if (erpSltz.ErpSltza == null)
            throw new ArgumentNullException(nameof(erpSltz.ErpSltza), "收料单主表数据不能为空");
 
        // 事务内处理主从表保存
        return UseTransaction(db =>
        {
            return Save(db, erpSltz) ? 1 : 0;
        }) > 0;
    }
 
    /// <summary>
    /// 提前获取或生成MES主表ID(修复:用事务内db查询)
    /// </summary>
    private Guid GetOrCreateMainId(SqlSugarScope db, ErpSltza erpMain)
    {
        if (string.IsNullOrEmpty(erpMain.billNo))
            throw new ArgumentException("ERP收料单单据号不能为空,无法确定主表唯一性", nameof(erpMain.billNo));
 
        // 修复:用事务内的db查询,而非Context
        var existingMain = db.Queryable<MesInvItemArn>()
            .Where(m => m.BillNo == erpMain.billNo)
            .First();
 
        return existingMain != null 
            ? existingMain.Id 
            : Guid.NewGuid();
    }
 
    /// <summary>
    /// 处理收料单新增/更新(主表+明细)
    /// </summary>
    private bool HandleSaveOrUpdate(SqlSugarScope db, MesInvItemArn mesMain, List<MesInvItemArnDetail> mesDetails, Guid mainId)
    {
        mesMain.Id = mainId;
        bool isMainExist = db.Queryable<MesInvItemArn>().Where(m => m.Id == mainId).Any();
        int mainOperateResult;
 
        if (isMainExist)
        {
            mainOperateResult = db.Updateable(mesMain)
                .IgnoreColumns(m => new { m.CreateDate })
                .Where(m => m.Id == mainId)
                .ExecuteCommand();
        }
        else
        {
            mesMain.CreateDate = DateTime.Now;
            mainOperateResult = db.Insertable(mesMain).ExecuteCommand();
        }
 
        // 处理明细
        int deleteOldDetailResult = db.Deleteable<MesInvItemArnDetail>()
            .Where(d => d.Mid == mainId)
            .ExecuteCommand();
 
        int insertNewDetailResult = mesDetails.Count > 0
            ? db.Insertable(mesDetails).ExecuteCommand()
            : 1;
 
        return mainOperateResult > 0 && (deleteOldDetailResult >= 0 && insertNewDetailResult > 0);
    }
 
    /// <summary>
    /// 处理收料单删除(主表+明细)
    /// </summary>
    private bool HandleDelete(SqlSugarScope db, MesInvItemArn mesMain, List<MesInvItemArnDetail> mesDetails, Guid mainId)
    {
        db.Deleteable<MesInvItemArnDetail>().Where(d => d.Mid == mainId).ExecuteCommand();
        int mainDeleteResult = db.Deleteable<MesInvItemArn>().Where(m => m.Id == mainId).ExecuteCommand();
        return mainDeleteResult >= 0;
    }
 
    /// <summary>
    /// ERP主表映射到MES主表(修复:取消关键字段注释,修正FType逻辑)
    /// </summary>
    private MesInvItemArn MapErpSltzaToMesInvItemArn(ErpSltza erpMain, Guid mainId)
    {
        // 单据日期转换
        DateTime.TryParse(erpMain.FDate, out DateTime parsedDate);
        // 是否SRM转换(0-否,1-是)
        int.TryParse(erpMain.F_ZJXF_sfgx, out int isSrm);
        // 供应商ID转换(字符串直接赋值,匹配MES字段类型)
        string suppId = string.IsNullOrEmpty(erpMain.SupplierId) ? null : erpMain.SupplierId.Trim();
        // 修复:“是否委外”逻辑(假设ERP的fType是“1”=是,“0”=否,或bool字符串)
        bool isOutsourcing = false;
        if (!string.IsNullOrEmpty(erpMain.fType))
        {
            isOutsourcing = erpMain.fType.Trim() == "1" || erpMain.fType.Trim().Equals("true", StringComparison.OrdinalIgnoreCase);
        }
 
        return new MesInvItemArn
        {
            // 修复:取消关键字段注释,补充赋值
            Id = mainId,
            BillNo = erpMain.billNo?.Trim() ?? throw new ArgumentException("收料单单据号不能为空"),
            SuppId = suppId,
            CreateDate = parsedDate == DateTime.MinValue ? null : (DateTime?)parsedDate,
            Remark = erpMain.Remark?.Trim(),
            IsSrm = isSrm,
            EbelnK3id = erpMain.erpId?.Trim(), // ERP主表ID(对应ebeln_k3id)
            CreateBy = erpMain.createBy?.Trim() ?? "SYSTEM", // 默认为系统
            FType = isOutsourcing, // 修复:正确的是否委外逻辑
            ReceiveOrgId = erpMain.ReceiveOrgId?.Trim(),
            // LastUpdateUser = erpMain.FCreatorId?.Trim() ?? "SYSTEM",
            // LastUpdateTime = DateTime.Now,
            // IsOut = false, // 初始未出库
            // Status = false // 初始未审核
        };
    }
 
    /// <summary>
    /// ERP明细映射到MES明细(修复:取消关键字段注释,修正EbelnK3id转换)
    /// </summary>
    private List<MesInvItemArnDetail> MapErpSltzBListToMesInvItemArnDetail(List<ErpSltzBList> erpDetails, Guid mainId)
    {
        return erpDetails.Select(erpDetail =>
        {
            // 数值类型安全转换
            int.TryParse(erpDetail.LineNo, out int lineNo); // 明细主键
            int.TryParse(erpDetail.ProductCode, out int itemId); // 物料编码
            decimal.TryParse(erpDetail.PurchaseQty, out decimal purchaseQty); // 采购订单数量
            decimal.TryParse(erpDetail.DeliveryQty, out decimal deliveryQty); // 本次应收数量
            decimal.TryParse(erpDetail.IncludeQty, out decimal includeQty); // 本次实收数量
            // 修复:用采购单ID字段(ebeln_k3id)转int,而非源单单号
            int.TryParse(erpDetail.FSrcBillNo, out int ebelnK3id); 
            int.TryParse(erpDetail.FSrcBillLine, out int lineK3id); // 采购单行ID
            bool.TryParse(erpDetail.urgentFlag, out bool urgentFlag); // 急料标识
 
            return new MesInvItemArnDetail
            {
                // 修复:取消关键字段注释,补充赋值
            //    LineNo = lineNo, // 明细主键(必须赋值)
                Mid = mainId, // 外键(关联主表ID,必须赋值)
                Ebeln = erpDetail.FBillNo?.Trim(), // 采购单号
                ItemId = itemId,
                EbelnQty = purchaseQty,
                SubQty = deliveryQty,
                Quantity = includeQty,
              //  PurchaseUnit = erpDetail.PurchaseUnit?.Trim(), // 采购单位(补充赋值)
              //  InventoryUnit = erpDetail.InventoryUnit?.Trim(), // 库存单位(补充赋值)
                Memo = erpDetail.Remark?.Trim(),
                EbelnK3id = ebelnK3id, // 修复:正确的采购单ID转换
                LineK3id = lineK3id,
             //   SalesOrderId = erpDetail.SalesOrderId?.Trim(), // 销售订单号(补充赋值)
              //  FMtoNo = erpDetail.FMtoNo?.Trim(), // 计划跟踪号(补充赋值)
             //   FLot = erpDetail.FLot?.Trim(), // 批号(补充赋值)
                UrgentFlag = urgentFlag
                //FStockId = erpDetail.DepotId?.Trim() // 收货仓库编号
            };
        }).ToList();
    }
 
    /// <summary>
    /// 按单据号查询MES收料单(主表+明细)
    /// </summary>
    public (MesInvItemArn main, List<MesInvItemArnDetail> details) GetByBillNo(string billNo)
    {
        if (string.IsNullOrEmpty(billNo))
            throw new ArgumentNullException(nameof(billNo), "查询条件单据号不能为空");
 
        var main = Context.Queryable<MesInvItemArn>()
            .Where(m => m.BillNo == billNo)
            .First();
 
        var details = main != null
            ? Context.Queryable<MesInvItemArnDetail>()
                .Where(d => d.Mid == main.Id)
                .ToList()
            : new List<MesInvItemArnDetail>();
 
        return (main, details);
    }
}