kyy
2025-08-19 04632ab8fee0eb716ead13f41b8b6235f98a9a31
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
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;
 
public class MesCgthSqManager : Repository<MesCgthSq>
{
    /// <summary>
    /// 批量保存采购退货单(主表+明细)
    /// </summary>
    public bool SaveList(List<ErpCgth> erpCgthList)
    {
        if (erpCgthList == null || !erpCgthList.Any())
            throw new ArgumentNullException(nameof(erpCgthList), "待保存的退货单列表不能为空");
 
        // 逐条处理,全部成功才返回true(事务内批量处理更优,此处保持原有逻辑)
        var result = erpCgthList.Select(Save).ToList();
        return result.All(b => b);
    }
 
    /// <summary>
    /// 保存采购退货单(主表+明细)
    /// </summary>
    public bool Save(ErpCgth erpCgth)
    {
        if (erpCgth == null)
            throw new ArgumentNullException(nameof(erpCgth), "退货单数据不能为空");
        if (erpCgth.ErpCgtha == null)
            throw new ArgumentNullException(nameof(erpCgth.ErpCgtha), "退货单主表数据不能为空");
 
        // 提取主表和明细表DTO
        var erpMain = erpCgth.ErpCgtha;
        var erpDetails = erpCgth.ErpCgthBList ?? new List<ErpCgthBList>(); // 避免明细为null
 
        // 步骤1:映射主表基础数据(暂不处理Id)
        var mesMain = MapErpCgthaToMesCgthSq(erpMain);
 
        // 步骤2:提前确定主表Id(核心修正:在映射明细表前获取/生成Id)
        Guid mainId = GetOrCreateMainId(mesMain);
 
        // 步骤3:用确定的mainId映射明细表(确保Mid=mainId)
        var mesDetails = MapErpCgthBToMesCgthSqDetail(erpDetails, mainId);
 
        // 步骤4:事务内处理主从表保存
        return UseTransaction(db =>
        {
            switch (erpMain.TYPE)
            {
                case "1": // 新增
                case "2": // 更新
                case "4": // 其他新增/更新类型
                case "5": // 提交
                    return SaveOrUpdateData(db, mesMain, mesDetails, mainId) ? 1 : 0;
                case "3": // 删除
                case "6": // 撤销
                    return DeleteData(db, mesMain, mesDetails, mainId) ? 1 : 0;
                default:
                    throw new NotImplementedException($"未实现的操作类型:{erpMain.TYPE}");
            }
        }) > 0;
    }
 
    /// <summary>
    /// 提前获取或生成主表Id(确保在映射明细表前确定)
    /// </summary>
    private Guid GetOrCreateMainId(MesCgthSq mesMain)
    {
        // 优先通过单据号查询已有主表(更新场景)
        var existingMain = Context.Queryable<MesCgthSq>()
            .Where(m => m.BillNo == mesMain.BillNo)
            .First();
 
        if (existingMain != null)
        {
            // 已存在:返回数据库中的Id
            return existingMain.Id;
        }
        else
        {
            // 不存在:生成新Id(新增场景)
            return Guid.NewGuid();
        }
    }
 
    /// <summary>
    /// 新增或更新数据(主表+明细)
    /// </summary>
    private bool SaveOrUpdateData(SqlSugarScope db, MesCgthSq mesMain, List<MesCgthSqDetail> mesDetails, Guid mainId)
    {
        // 绑定主表Id(使用提前确定的mainId)
        mesMain.Id = mainId;
 
        // 处理主表:新增或更新
        bool isExist = db.Queryable<MesCgthSq>().Where(m => m.BillNo == mesMain.BillNo).Any();
        int mainResult;
 
        if (isExist)
        {
            // 更新:按Id匹配(避免单据号重复导致错误)
            mainResult = db.Updateable(mesMain)
                .IgnoreColumns(m => new { m.CreateDate }) // 不更新创建时间
                .Where(m => m.Id == mainId)
                .ExecuteCommand();
        }
        else
        {
            // 新增:使用提前生成的Id
            mainResult = db.Insertable(mesMain).ExecuteCommand();
        }
 
        // 处理明细表:先删旧数据,再插新数据(确保数据同步)
        // 1. 删除当前主表关联的旧明细
        int deleteOldDetailResult = db.Deleteable<MesCgthSqDetail>()
            .Where(d => d.Mid == mainId)
            .ExecuteCommand();
 
        // 2. 插入新明细(Mid已=mainId)
        int insertDetailResult = mesDetails.Count > 0
            ? db.Insertable(mesDetails).ExecuteCommand()
            : 1; // 无明细时视为成功
 
        // 校验结果(主表必须成功,明细删除/插入至少有一个成功)
        return mainResult > 0 && (deleteOldDetailResult >= 0 && insertDetailResult > 0);
    }
 
    /// <summary>
    /// 删除数据(主表+明细)
    /// </summary>
    private bool DeleteData(SqlSugarScope db, MesCgthSq mesMain, List<MesCgthSqDetail> mesDetails, Guid mainId)
    {
        // 1. 删除明细(按主表Id删除)
        int detailResult = db.Deleteable<MesCgthSqDetail>()
            .Where(d => d.Mid == mainId)
            .ExecuteCommand();
 
        // 2. 删除主表(按Id删除)
        int mainResult = db.Deleteable<MesCgthSq>()
            .Where(m => m.Id == mainId)
            .ExecuteCommand();
 
        // 允许明细原本不存在(detailResult=0),但主表必须删除成功
        return mainResult > 0;
    }
 
    /// <summary>
    /// 主表映射(仅处理基础字段,Id由GetOrCreateMainId确定)
    /// </summary>
    private MesCgthSq MapErpCgthaToMesCgthSq(ErpCgtha erpMain)
    {
        return new MesCgthSq
        {
            // Id暂不赋值(由GetOrCreateMainId后续确定)
            ErpId = erpMain.ERPID, // ERP主表ID
            BillNo = erpMain.billNo ?? throw new ArgumentNullException(nameof(erpMain.billNo), "单据编号不能为空"),
            Type = erpMain.TYPE,
            FDate = erpMain.FDate,
            FDocumentStatus = erpMain.FDocumentStatus,
            FSupplierId = erpMain.FSupplierID,
            FBillTypeId = erpMain.FBillTypeID,
            FBusinessType = erpMain.FBusinessType,
            ReturnType = erpMain.FMRTYPE,
            ReturnMethod = erpMain.FMRMODE,
            CreateBy = erpMain.FCreatorId,
            FPurchaseOrgId = erpMain.FPurchaseOrgId,
            ThOrgId = erpMain.FStockOrgId,
            FRequireOrgId = erpMain.FRequireOrgId,
            FMRDeptId = erpMain.FMRDeptId,
            FStockerId = erpMain.FSTOCKERID,
            FPurchaserId = erpMain.FPURCHASERID,
            FMRReason = erpMain.FMRREASON,
            FPurchaseDeptId = erpMain.FPURCHASEDEPTID,
            FPurchaserGroupId = erpMain.FPURCHASERGROUPID,
            FACCTYPE = erpMain.FACCTYPE,
            FCreateDate = erpMain.FCreateDate,
            FWPVTINTEGERL6W = erpMain.F_WPVT_INTEGER_L6W,
 
            // 供应商ID(安全转换)
            SuppId = !string.IsNullOrEmpty(erpMain.FSupplierID)
                     && int.TryParse(erpMain.FSupplierID, out int suppId)
                ? suppId
                : null,
 
            // 系统字段(创建时间仅新增时赋值,更新时不覆盖)
            CreateDate = DateTime.Now,
            LastUpdateTime = DateTime.Now
        };
    }
 
    /// <summary>
    /// 明细表映射(使用提前确定的mainId作为Mid)
    /// </summary>
    private List<MesCgthSqDetail> MapErpCgthBToMesCgthSqDetail(List<ErpCgthBList> erpDetails, Guid mainId)
    {
        return erpDetails.Select(erpDetail => new MesCgthSqDetail
        {
            Mid = mainId, // 直接使用提前确定的mainId(确保非全零)
 
            // ERP明细ID(安全转换)
            ErpId = !string.IsNullOrEmpty(erpDetail.ERPID)
                    && int.TryParse(erpDetail.ERPID, out int erpId)
                ? erpId
                : null,
 
            // 外部系统ID(安全转换)
            Eid = !string.IsNullOrEmpty(erpDetail.EID)
                  && int.TryParse(erpDetail.EID, out int eid)
                ? eid
                : null,
 
            FsrcBillNo = erpDetail.FSRCBillNo,
            FsrcBillTypeId = erpDetail.FSRCBillTypeId,
 
            // 物料ID(安全转换)
            ItemId = !string.IsNullOrEmpty(erpDetail.FMATERIALID)
                     && int.TryParse(erpDetail.FMATERIALID, out int itemId)
                ? itemId
                : null,
 
            FUnitId = erpDetail.FUnitID,
 
            // 仓库ID(安全转换)
            DepotId = !string.IsNullOrEmpty(erpDetail.FSTOCKID)
                      && long.TryParse(erpDetail.FSTOCKID, out long depotId)
                ? depotId
                : null,
 
            FstockLocId = erpDetail.FSTOCKLOCID,
            FLot = erpDetail.FLot,
            SqNum = erpDetail.FRMREALQTY, // 假设FRMREALQTY是数值类型(如decimal)
            Remark = erpDetail.FNOTE,
            FMtoNo = erpDetail.FMtoNo,
            IsFinish = false // 初始未完成
        }).ToList();
    }
}