cl
1 天以前 2fa1c824c63048b49e45d867191ab3645aeaf3a4
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
package com.vincent.rsf.server.api.service.impl;
 
import com.vincent.rsf.server.api.config.RemotesInfoProperties;
import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionLine;
import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionRequest;
import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
import com.vincent.rsf.server.api.controller.erp.params.InventoryAdjustReportParam;
import com.vincent.rsf.server.api.feign.CloudWmsErpFeignClient;
import com.vincent.rsf.server.api.integration.dap.DapIlcwmsResponseNormalizer;
import com.vincent.rsf.server.api.service.CloudWmsReportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 立库侧请求云仓:ICusStockService 入库/出库/调拨完成反馈;9.2 增减调整仍为 /api/report/inventoryAdjust,报文同为 {data:[]}。
 */
@Slf4j
@Service
public class CloudWmsReportServiceImpl implements CloudWmsReportService {
 
    @Autowired
    private RemotesInfoProperties erpApi;
 
    @Autowired
    private CloudWmsErpFeignClient cloudWmsErpFeignClient;
 
    @Override
    public Map<String, Object> syncMatnrsToCloud(Object body) {
        if (!isCloudWmsConfigured()) {
            log.warn("ErpApi(云仓WMS) 未配置 host,跳过物料基础信息同步");
            return stubSuccess("云仓地址未配置,未实际同步");
        }
        return cloudWmsErpFeignClient.syncMatnrs(body != null ? body : new HashMap<>());
    }
 
    @Override
    public Map<String, Object> reportInOutResult(InOutResultReportParam param) {
        if (param == null) {
            return resultMap(400, "参数不能为空", null);
        }
        if (!isCloudWmsConfigured()) {
            log.warn("ErpApi(云仓WMS) 未配置 host,跳过 9.1 入/出库结果上报,订单:{}", param.getOrderNo());
            return stubSuccess("云仓地址未配置,未实际上报");
        }
        String err = validateDapBase();
        if (err != null) {
            return resultMap(400, err, null);
        }
        boolean inbound = param.getInbound() == null || Boolean.TRUE.equals(param.getInbound());
        DapIlcwmsCompletionRequest req = new DapIlcwmsCompletionRequest()
                .setData(Collections.singletonList(buildInOutLine(param, inbound)));
        Map<String, Object> raw = inbound
                ? cloudWmsErpFeignClient.cusInventoryCompletionReport(req)
                : cloudWmsErpFeignClient.cusOutboundCompletionReport(req);
        return DapIlcwmsResponseNormalizer.toNotifyFormat(raw);
    }
 
    @Override
    public Map<String, Object> reportInventoryAdjust(InventoryAdjustReportParam param) {
        if (param == null) {
            return resultMap(400, "参数不能为空", null);
        }
        if (!isCloudWmsConfigured()) {
            log.warn("ErpApi(云仓WMS) 未配置 host,跳过 9.2 库存调整上报,物料:{}", param.getMatNr());
            return stubSuccess("云仓地址未配置,未实际上报");
        }
        String err = validateDapBase();
        if (err != null) {
            return resultMap(400, err, null);
        }
        Integer changeType = param.getChangeType();
        if (changeType == null) {
            return resultMap(400, "changeType 不能为空", null);
        }
        DapIlcwmsCompletionRequest req = new DapIlcwmsCompletionRequest();
        if (changeType == 3) {
            String baseSeq = StringUtils.isNotBlank(param.getDocSeqNo()) ? param.getDocSeqNo() : "1";
            List<DapIlcwmsCompletionLine> lines = new ArrayList<>(2);
            lines.add(buildAdjustLine(param, false, true, baseSeq + "-O"));
            lines.add(buildAdjustLine(param, true, false, baseSeq + "-I"));
            req.setData(lines);
        } else if (changeType == 1) {
            req.setData(Collections.singletonList(buildAdjustLine(param, true, false, null)));
        } else if (changeType == 2) {
            req.setData(Collections.singletonList(buildAdjustLine(param, false, true, null)));
        } else {
            return resultMap(400, "不支持的 changeType:" + changeType, null);
        }
        Map<String, Object> raw = changeType == 3
                ? cloudWmsErpFeignClient.stockTransferCompleted(req)
                : cloudWmsErpFeignClient.reportInventoryAdjust(req);
        return changeType == 3
                ? DapIlcwmsResponseNormalizer.toNotifyFormat(raw)
                : DapIlcwmsResponseNormalizer.toNotifyFormatFlexible(raw);
    }
 
    private DapIlcwmsCompletionLine buildInOutLine(InOutResultReportParam param, boolean inbound) {
        RemotesInfoProperties.Dap dap = erpApi.getDap();
        CloudMatnrParts matnrParts = parseCloudMatnr(param.getMatNr());
        DapIlcwmsCompletionLine line = new DapIlcwmsCompletionLine()
                .setOrgNo(dap.getOrgNo())
                .setDocType(inbound ? dap.getDocTypeIn() : dap.getDocTypeOut())
                .setDocNo(param.getOrderNo())
                .setDocSeqNo(StringUtils.isNotBlank(param.getLineId()) ? param.getLineId() : "1")
                // 按云仓规则拆分物料编码
                .setItemNo(matnrParts.getItemNo())
                .setQty(parseQty(param.getQty()))
                .setUnitNo(dap.getUnitNo())
                .setCombinationLotNo(matnrParts.getCombinationLotNo())
                .setBarcode(matnrParts.getBarcode());
        if (inbound) {
            line.setInWarehouseNo(param.getWareHouseId()).setInCellNo(param.getLocId());
        } else {
            line.setOutWarehouseNo(param.getWareHouseId()).setOutCellNo(param.getLocId());
        }
        return line;
    }
 
    /**
     * @param fillIn 是否填入库储位
     * @param fillOut 是否填出库储位
     * @param docSeqOverride 非空时用作项次(移库第二行等)
     */
    private DapIlcwmsCompletionLine buildAdjustLine(InventoryAdjustReportParam param, boolean fillIn, boolean fillOut, String docSeqOverride) {
        RemotesInfoProperties.Dap dap = erpApi.getDap();
        String docType = resolveAdjustDocType(param, dap);
        String docNo = StringUtils.isNotBlank(param.getDocNo()) ? param.getDocNo() : "ADJ";
        String docSeq = docSeqOverride != null ? docSeqOverride
                : (StringUtils.isNotBlank(param.getDocSeqNo()) ? param.getDocSeqNo() : "1");
        String unit = StringUtils.isNotBlank(param.getUnitNo()) ? param.getUnitNo() : dap.getUnitNo();
        CloudMatnrParts matnrParts = parseCloudMatnr(param.getMatNr());
        DapIlcwmsCompletionLine line = new DapIlcwmsCompletionLine()
                .setOrgNo(dap.getOrgNo())
                .setDocType(docType)
                .setDocNo(docNo)
                .setDocSeqNo(docSeq)
                // 按云仓规则拆分物料编码
                .setItemNo(matnrParts.getItemNo())
                .setQty(parseQty(param.getQty()))
                .setUnitNo(unit)
                .setCombinationLotNo(matnrParts.getCombinationLotNo())
                .setBarcode(matnrParts.getBarcode());
        if (fillIn) {
            line.setInWarehouseNo(param.getWareHouseId());
            line.setInCellNo(StringUtils.isNotBlank(param.getTargetLocId()) ? param.getTargetLocId() : param.getSourceLocId());
        }
        if (fillOut) {
            line.setOutWarehouseNo(param.getWareHouseId());
            line.setOutCellNo(StringUtils.isNotBlank(param.getSourceLocId()) ? param.getSourceLocId() : param.getTargetLocId());
        }
        return line;
    }
 
    private static String resolveAdjustDocType(InventoryAdjustReportParam param, RemotesInfoProperties.Dap dap) {
        if (StringUtils.isNotBlank(param.getDocType())) {
            return param.getDocType();
        }
        Integer ct = param.getChangeType();
        if (ct != null && ct == 2) {
            return dap.getDocTypeOut();
        }
        if (ct != null && ct == 3) {
            return dap.getDocTypeAdj();
        }
        return dap.getDocTypeIn();
    }
 
    // private static String resolveBarcode(InOutResultReportParam param) {
    //     if (StringUtils.isNotBlank(param.getBarcode())) {
    //         return param.getBarcode();
    //     }
    //     if (StringUtils.isNotBlank(param.getPalletId())) {
    //         return param.getPalletId();
    //     }
    //     if (param.getMatNr() != null && param.getLocId() != null) {
    //         return param.getMatNr() + ":" + param.getLocId();
    //     }
    //     return param.getMatNr();
    // }
    //
    // private static String resolveAdjustBarcode(InventoryAdjustReportParam param) {
    //     if (StringUtils.isNotBlank(param.getBarcode())) {
    //         return param.getBarcode();
    //     }
    //     if (StringUtils.isNotBlank(param.getPalletId())) {
    //         return param.getPalletId();
    //     }
    //     return param.getMatNr();
    // }
 
    /**
     * 云仓回报字段映射:三段式取前两段,barcode 保留原串。
     */
    private static CloudMatnrParts parseCloudMatnr(String matNr) {
        if (StringUtils.isBlank(matNr)) {
            return new CloudMatnrParts(null, null, null);
        }
        String[] arr = matNr.split("#", -1);
        if (arr.length >= 3) {
            return new CloudMatnrParts(arr[0], arr[1], matNr);
        }
        return new CloudMatnrParts(matNr, null, matNr);
    }
 
    private static class CloudMatnrParts {
        private final String itemNo;
        private final String combinationLotNo;
        private final String barcode;
 
        private CloudMatnrParts(String itemNo, String combinationLotNo, String barcode) {
            this.itemNo = itemNo;
            this.combinationLotNo = combinationLotNo;
            this.barcode = barcode;
        }
 
        public String getItemNo() {
            return itemNo;
        }
 
        public String getCombinationLotNo() {
            return combinationLotNo;
        }
 
        public String getBarcode() {
            return barcode;
        }
    }
 
    private static Double parseQty(String q) {
        if (StringUtils.isBlank(q)) {
            return 0d;
        }
        try {
            return Double.parseDouble(q.trim());
        } catch (NumberFormatException e) {
            return 0d;
        }
    }
 
    private String validateDapBase() {
        RemotesInfoProperties.Dap d = erpApi.getDap();
        if (d == null || StringUtils.isBlank(d.getOrgNo())) {
            return "未配置 platform.erp.dap.org-no";
        }
        return null;
    }
 
    private boolean isCloudWmsConfigured() {
        String host = erpApi.getHost();
        return host != null && !host.trim().isEmpty();
    }
 
    private Map<String, Object> stubSuccess(String msg) {
        Map<String, Object> data = new HashMap<>();
        data.put("result", "SUCCESS");
        return resultMap(200, msg, data);
    }
 
    private Map<String, Object> resultMap(int code, String msg, Map<String, Object> data) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        map.put("msg", msg);
        map.put("data", data);
        return map;
    }
}