1
12 小时以前 34503a2e9a29418346a4ac8f84170ab8f4321d6e
rsf-open-api/src/main/java/com/vincent/rsf/openApi/service/phyz/impl/ErpReportServiceImpl.java
@@ -1,32 +1,65 @@
package com.vincent.rsf.openApi.service.phyz.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.CoercionAction;
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.openApi.config.PlatformProperties;
import com.vincent.rsf.openApi.entity.app.OpenApiOrder;
import com.vincent.rsf.openApi.entity.app.OpenApiOrderItem;
import com.vincent.rsf.openApi.entity.app.OpenApiOrderItemMap;
import com.vincent.rsf.openApi.entity.app.OpenApiOrderReportEvent;
import com.vincent.rsf.openApi.entity.constant.WmsConstant;
import com.vincent.rsf.openApi.entity.dto.CommonResponse;
import com.vincent.rsf.openApi.entity.phyz.ErpReportParams;
import com.vincent.rsf.openApi.entity.phyz.*;
import com.vincent.rsf.openApi.entity.params.ReportDataParam;
import com.vincent.rsf.openApi.entity.params.ReportParams;
import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapMapper;
import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapper;
import com.vincent.rsf.openApi.mapper.OpenApiOrderMapper;
import com.vincent.rsf.openApi.mapper.OpenApiOrderReportEventMapper;
import com.vincent.rsf.openApi.service.WmsErpService;
import com.vincent.rsf.openApi.service.phyz.ErpReportService;
import com.vincent.rsf.openApi.utils.ParamsMapUtils;
import com.vincent.rsf.openApi.utils.SslUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.client.config.RequestConfig;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.lang.reflect.Field;
import java.security.cert.X509Certificate;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@@ -34,10 +67,26 @@
    private static String ERP_REPORT_URL;
    private CloseableHttpClient httpClient;
    @Resource
    private PlatformProperties.ErpApi erpApi;
    @Resource
    private PlatformProperties.WmsApi wmsApi;
    @Resource
    private WmsErpService wmsErpService;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private OpenApiOrderMapper openApiOrderMapper;
    @Resource
    private OpenApiOrderItemMapper openApiOrderItemMapper;
    @Resource
    private OpenApiOrderItemMapMapper openApiOrderItemMapMapper;
    @Resource
    private OpenApiOrderReportEventMapper openApiOrderReportEventMapper;
    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
    @PostConstruct
@@ -45,18 +94,854 @@
        ERP_REPORT_URL = erpApi.getErpUrl();
    }
    @Override
    public String syncMaterial(List<Material> materialList){
        if (materialList.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_MATNRS;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        // Material -> BaseMatParms 字段一一对应后再下发
        List<Map<String, Object>> baseMatParamsList = materialToBaseMatParams(materialList);
        HttpEntity httpEntity2 = new HttpEntity<>(baseMatParamsList, headers);//cs
        // sync/warehouse
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs
        log.info("同步物料信息返回结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
        } else {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
            try {
                CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
                if (result.getCode() == 200) {
//                    JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(result.getData()));
                    return "200";
                } else {
                    return result.getMsg();
//                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                return e.getMessage();
//                throw new CoolException(e.getMessage());
            }
        }
    }
    /**
     * Material 字段映射为 server 端 BaseMatParms 字段
     */
    private List<Map<String, Object>> materialToBaseMatParams(List<Material> materialList) {
        List<Map<String, Object>> mappedList = new ArrayList<>();
        for (Material material : materialList) {
            if (Objects.isNull(material)) {
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("maktx", material.getMakTx());
            map.put("matnr", material.getMatNr());
            map.put("groupName", material.getGroupName());
            map.put("model", material.getModel());
            map.put("weight", material.getWeight() == null ? null : material.getWeight().toString());
            map.put("color", material.getColor());
            map.put("size", material.getSize());
            map.put("spec", material.getSpec());
            map.put("describle", material.getDescribe());
            map.put("unit", material.getUnit());
            map.put("operateType", material.getOperateType());
            mappedList.add(map);
        }
        return mappedList;
    }
    @Override
    public String syncWareHouse(List<Warehouse> warehouseList){
        if (warehouseList.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_WAREHOUSE;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        // Warehouse -> WarehouseParams 字段一一对应后再下发
        List<Map<String, Object>> warehouseParamsList = warehouseToWarehouseParams(warehouseList);
        HttpEntity httpEntity2 = new HttpEntity<>(warehouseParamsList, headers);//cs
        // sync/warehouse
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs
        log.info("同步仓库信息返回结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
        } else {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
            try {
                CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
                if (result.getCode() == 200) {
//                    JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(result.getData()));
                    return "200";
                } else {
                    return result.getMsg();
//                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                return e.getMessage();
//                throw new CoolException(e.getMessage());
            }
        }
    }
    @Override
    public String syncCustomer(List<Customer> customerList){
        if (customerList.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_COMPANIES;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        // Customer -> CompaniesParam 字段一一对应后再下发
        List<Map<String, Object>> companiesParamsList = customerToCompaniesParams(customerList);
        HttpEntity httpEntity2 = new HttpEntity<>(companiesParamsList, headers);//cs
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs
        log.info("同步客户信息返回结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
        } else {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
            try {
                CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
                if (result.getCode() == 200) {
                    return "200";
                } else {
                    return result.getMsg();
                }
            } catch (JsonProcessingException e) {
                return e.getMessage();
            }
        }
    }
    @Override
    public String syncSupplier(List<Supplier> supplierList){
        if (supplierList.isEmpty()) {
            throw new CoolException("参数不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.SYNC_COMPANIES;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        // Supplier -> supplierParams 字段一一对应后再下发
        List<Map<String, Object>> supplierParamsList = customerToSupplierParams(supplierList);
        HttpEntity httpEntity2 = new HttpEntity<>(supplierParamsList, headers);//cs
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs
        log.info("同步客户信息返回结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
        } else {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
            try {
                CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
                if (result.getCode() == 200) {
                    return "200";
                } else {
                    return result.getMsg();
                }
            } catch (JsonProcessingException e) {
                return e.getMessage();
            }
        }
    }
    /**
     * Warehouse 字段映射为 server 端 WarehouseParams 字段
     */
    private List<Map<String, Object>> warehouseToWarehouseParams(List<Warehouse> warehouseList) {
        List<Map<String, Object>> mappedList = new ArrayList<>();
        for (Warehouse warehouse : warehouseList) {
            if (Objects.isNull(warehouse)) {
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("name", warehouse.getWareHouseName());
            map.put("code", warehouse.getWareHouseId());
            map.put("factory",  warehouse.getUseOrgName());
            map.put("factoryId",  warehouse.getUseOrgId());
            map.put("address", warehouse.getAddress());
            map.put("type", null);
            map.put("longitude", null);
            map.put("latitude", null);
            map.put("operateType", warehouse.getOperateType());
            mappedList.add(map);
        }
        return mappedList;
    }
    /**
     * Customer 字段映射为 server 端 CompaniesParam 字段
     */
    private List<Map<String, Object>> customerToCompaniesParams(List<Customer> customerList) {
        List<Map<String, Object>> mappedList = new ArrayList<>();
        int rowNum = 0;
        for (Customer customer : customerList) {
            rowNum++;
            if (Objects.isNull(customer)) {
                continue;
            }
            if (StringUtils.isBlank(customer.getCustomerId())) {
                throw new CoolException("客户同步失败:第" + rowNum + "行客户编码为空");
            }
            if (StringUtils.isBlank(customer.getCustomerName())) {
                throw new CoolException("客户同步失败:第" + rowNum + "行客户名称为空");
            }
            Map<String, Object> map = new HashMap<>();
            map.put("name", customer.getCustomerName());
            map.put("nameEn", null);
            map.put("breifCode", customer.getCustomerNickName());
            // server 端类型转换使用中文描述
            map.put("type", "客户");
            map.put("contact", customer.getContact());
            map.put("tel", customer.getTelephone());
            map.put("email", customer.getEmail());
            map.put("pcode", null);
            map.put("city", customer.getCustomerGroup());
            map.put("province", null);
            map.put("address", customer.getAddress());
            map.put("code", customer.getCustomerId());
            map.put("operateType", customer.getOperateType());
            mappedList.add(map);
        }
        return mappedList;
    }
    /**
     * Customer 字段映射为 server 端 CompaniesParam 字段
     */
    private List<Map<String, Object>> customerToSupplierParams(List<Supplier> supplierList) {
        List<Map<String, Object>> mappedList = new ArrayList<>();
        for (Supplier supplier : supplierList) {
            if (Objects.isNull(supplier)) {
                continue;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("name", supplier.getSupplierName());
            map.put("nameEn", null);
            map.put("breifCode", supplier.getSupplierName());
            // server 端类型转换使用中文描述
            map.put("type", supplier.getType());
            map.put("contact", supplier.getContact());
            map.put("tel", supplier.getTelephone());
            map.put("email", supplier.getEmail());
            map.put("pcode", null);
            map.put("city", supplier.getSupplierGroup());
            map.put("province", null);
            map.put("address", supplier.getAddress());
            map.put("code", supplier.getSupplierId());
            map.put("operateType", supplier.getOperateType());
            mappedList.add(map);
        }
        return mappedList;
    }
    @Override
    public String addOrderToServer(Order order) {
        if (Objects.isNull(order.getOrderNo()) || order.getOrderNo().isEmpty()) {
            throw new CoolException("订单号不能为空!!");
        }
        /**WMS基础配置链接*/
        String wmsUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.MODIFY_ORDER_DETLS;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        headers.add("api-version", "v2.0");
        List<Map<String, Object>> maps = new ArrayList<>();
        Map<String, Object> mapParams = new HashMap<>();
//        mapParams.put("orderNo", params.getOrderNo());
//        mapParams.put("anfme", params.getAnfme());
//        mapParams.put("type", params.getType());
//        mapParams.put("wkType", params.getWkType());
//        mapParams.put("exceStatus", params.getExceStatus());
//        mapParams.put("orderItems", params.getOrderItems());
//        maps.add(mapParams);
        JSONObject params = JSONObject.parseObject(JSON.toJSONString(order));
        JSONObject mappedData = ParamsMapUtils.apiMaps("erp", "orderId", params);
        mappedData.put("updateBy", "erp");
        mapParams = objectToMap(mappedData);
        maps.add(mapParams);
        log.info("修改订单信息及状态: {}, 请求参数: {}", wmsUrl, JSONArray.toJSONString(maps));
        HttpEntity<List<Map<String, Object>>> httpEntity = new HttpEntity<>(maps, headers);
        ArrayList<Order> orders = new ArrayList<>();
        orders.add(order);
        HttpEntity httpEntity2 = new HttpEntity<>(orders, headers);//cs
        // asnOrder/items/save
        ResponseEntity<String> exchange = restTemplate.exchange(wmsUrl, HttpMethod.POST, httpEntity2, String.class);//cs
        log.info("订单修改返回结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
            throw new CoolException("查询失败!!");
        } else {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
            try {
                CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
                if (result.getCode() == 200) {
//                    JSONObject object = JSONObject.parseObject(JSONObject.toJSONString(result.getData()));
                    return "200";
                } else {
                    return result.getMsg();
//                    throw new CoolException("查询失败!!");
                }
            } catch (JsonProcessingException e) {
                return e.getMessage();
//                throw new CoolException(e.getMessage());
            }
        }
    // 登录参数依次为账套ID、用户名、应用ID、时间戳、签名信息、语言ID
    public void loginBySign() throws UnsupportedEncodingException, NoSuchAlgorithmException {
        String url = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginBySign.common.kdsvc";
        JSONObject params = new JSONObject();
        params.put("parameters", loginParams());
        JSONObject result = postRequest(url, params, false);
//        ErpOpParams erpOpParams = new ErpOpParams();
//        erpOpParams.set
//
//        wmsErpService.updateOrderDetl(ErpOpParams params);
//        CommonResponse updateOrderDetl()
//
//        asnOrderService.saveOrderAndItems(params, getLoginUserId());
    }
    @Override
    public String addOrderToServerNew(Order order) {
        if (Objects.isNull(order) || StringUtils.isBlank(order.getOrderNo())) {
            throw new CoolException("订单号不能为空!!");
        }
        if (Objects.isNull(order.getOrderItems()) || order.getOrderItems().isEmpty()) {
            throw new CoolException("订单明细不能为空!!");
        }
        OpenApiOrder persistedOrder = saveOpenApiOrder(order);
        List<OpenApiOrderItem> persistedItems = saveOpenApiOrderItems(persistedOrder, order.getOrderItems());
        saveOpenApiOrderItemMappings(persistedOrder, persistedItems);
        Order mergedOrder = buildMergedOrder(order);
        String dispatchResult = addOrderToServer(mergedOrder);
        if (!"200".equals(dispatchResult)) {
            return dispatchResult;
        }
        return "200";
    }
    @Override
    public CommonResponse reportOrderNew(Object params) {
        if (Objects.isNull(params)) {
            throw new CoolException("参数不能为空!!");
        }
        JSONObject root = JSONObject.parseObject(JSON.toJSONString(params));
        String eventId = pickString(root, "eventId", "EventId");
        String taskNo = pickString(root, "taskNo", "TaskNo");
        String reportNo = pickString(root, "reportNo", "ReportNo");
        if (StringUtils.isBlank(eventId) && StringUtils.isBlank(taskNo) && StringUtils.isBlank(reportNo)) {
            throw new CoolException("幂等键不能为空(eventId/taskNo/reportNo)");
        }
        if (existsReportEvent(eventId, taskNo, reportNo)) {
            return CommonResponse.ok("重复回传已忽略");
        }
        OpenApiOrderReportEvent reportEvent = saveReportEvent(eventId, taskNo, reportNo, pickString(root, "orderNo", "WMSNO"), root.toJSONString());
        JSONArray dataArray = pickArray(root, "Data", "data");
        if (Objects.isNull(dataArray) || dataArray.isEmpty()) {
            return CommonResponse.error("回传明细为空");
        }
        int allocateCount = 0;
        int erpReportCount = 0;
        List<String> errors = new ArrayList<>();
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject row = dataArray.getJSONObject(i);
            String orderNo = pickString(row, "WMSNO", "wmsNo", "orderNo", "OrderNo");
            String matnrCode = pickString(row, "ItemCode", "itemCode", "matNr", "MatNr");
            String batch = pickString(row, "Batch", "batch", "GoodsNO", "goodsNo");
            BigDecimal doneQty = pickDecimal(row, "qty", "doneQty", "InQty", "OutQty");
            if (StringUtils.isBlank(orderNo) || StringUtils.isBlank(matnrCode) || doneQty.compareTo(ZERO) <= 0) {
                errors.add("第" + (i + 1) + "行缺少必要字段(WMSNO/ItemCode/数量)");
                continue;
            }
            doneQty = doneQty.setScale(2, RoundingMode.HALF_UP);
            try {
                int singleAllocated = allocateMergedDoneQty(orderNo, matnrCode, batch, doneQty);
                allocateCount += singleAllocated;
                erpReportCount += reportReadyLinesToErp(orderNo);
                refreshOrderFinishStatus(orderNo);
            } catch (Exception e) {
                log.error("处理回传失败,orderNo={}, matnr={}, batch={}", orderNo, matnrCode, batch, e);
                errors.add("第" + (i + 1) + "行处理失败:" + e.getMessage());
            }
        }
        if (!errors.isEmpty()) {
            reportEvent.setStatus(2);
            openApiOrderReportEventMapper.updateById(reportEvent);
            return CommonResponse.error("处理完成,但存在异常:" + String.join(" | ", errors));
        }
        reportEvent.setStatus(1);
        openApiOrderReportEventMapper.updateById(reportEvent);
        Map<String, Object> result = new HashMap<>();
        result.put("allocatedCount", allocateCount);
        result.put("erpReportCount", erpReportCount);
        return CommonResponse.ok(result);
    }
    private OpenApiOrder saveOpenApiOrder(Order order) {
        OpenApiOrder existing = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>()
                .eq(OpenApiOrder::getCode, order.getOrderNo())
                .last("limit 1"));
        BigDecimal totalQty = sumOrderItemQty(order.getOrderItems());
        Date businessTime = toDate(order.getBusinessTime());
        OpenApiOrder target = Objects.isNull(existing) ? new OpenApiOrder() : existing;
        target.setCode(order.getOrderNo())
                .setType(order.getType())
                .setWkType(order.getWkType())
                .setAnfme(totalQty)
                .setQty(ZERO)
                .setWorkQty(ZERO)
                .setExceStatus(0)
                .setStatus(1)
                .setBusinessTime(businessTime)
                .setOrderInternalCode(order.getOrderInternalCode())
                .setStationId(order.getStationId())
                .setStockDirect(order.getStockDirect())
                .setCustomerId(order.getCustomerId())
                .setCustomerName(order.getCustomerName())
                .setSupplierId(order.getSupplierId())
                .setSupplierName(order.getSupplierName())
                .setStockOrgId(order.getStockOrgId())
                .setStockOrgName(order.getStockOrgName())
                .setPurchaseOrgId(order.getPurchaseOrgId())
                .setPurchaseOrgName(order.getPurchaseOrgName())
                .setPurchaseUserId(order.getPurchaseUserId())
                .setPurchaseUserName(order.getPurchaseUserName())
                .setPrdOrgId(order.getPrdOrgId())
                .setPrdOrgName(order.getPrdOrgName())
                .setSaleOrgId(order.getSaleOrgId())
                .setSaleOrgName(order.getSaleOrgName())
                .setSaleUserId(order.getSaleUserId())
                .setSaleUserName(order.getSaleUserName());
        if (Objects.isNull(existing)) {
            openApiOrderMapper.insert(target);
        } else {
            openApiOrderMapper.updateById(target);
            openApiOrderItemMapper.delete(new LambdaQueryWrapper<OpenApiOrderItem>().eq(OpenApiOrderItem::getOrderId, target.getId()));
            openApiOrderItemMapMapper.delete(new LambdaQueryWrapper<OpenApiOrderItemMap>().eq(OpenApiOrderItemMap::getOrderId, target.getId()));
        }
        return target;
    }
    private List<OpenApiOrderItem> saveOpenApiOrderItems(OpenApiOrder order, List<OrderItem> orderItems) {
        List<OpenApiOrderItem> saved = new ArrayList<>();
        for (OrderItem src : orderItems) {
            OpenApiOrderItem target = new OpenApiOrderItem()
                    .setOrderId(order.getId())
                    .setOrderCode(order.getCode())
                    .setPlatItemId(src.getLineId())
                    .setPlatWorkCode(src.getPlanNo())
                    .setMatnrCode(src.getMatNr())
                    .setMaktx(src.getMakTx())
                    .setModel(src.getModel())
                    .setSpec(src.getSpec())
                    .setAnfme(toDecimal(src.getAnfme()))
                    .setStockUnit(src.getUnit())
                    .setWorkQty(ZERO)
                    .setQty(ZERO)
                    .setBatch(src.getBatch())
                    .setMemo(src.getMemo())
                    .setTargetWarehouseId(src.getTargetWarehouseId())
                    .setSourceWarehouseId(src.getSourceWarehouseId())
                    .setOwnerId(src.getOwnerId())
                    .setBaseUnit(src.getBaseUnit())
                    .setUseOrgId(src.getUseOrgId())
                    .setUseOrgName(src.getUseOrgName())
                    .setErpClsId(src.getErpClsId())
                    .setPriceUnitId(src.getPriceUnitId())
                    .setInStockType(src.getInStockType())
                    .setOwnerTypeId(src.getOwnerTypeId())
                    .setOwnerName(src.getOwnerName())
                    .setKeeperTypeId(src.getKeeperTypeId())
                    .setKeeperId(src.getKeeperId())
                    .setKeeperName(src.getKeeperName())
                    .setStatus(1)
                    .setDeleted(0);
            openApiOrderItemMapper.insert(target);
            saved.add(target);
        }
        return saved;
    }
    private void saveOpenApiOrderItemMappings(OpenApiOrder order, List<OpenApiOrderItem> items) {
        Map<String, List<OpenApiOrderItem>> grouped = items.stream().collect(Collectors.groupingBy(i -> mergeKey(i.getMatnrCode(), i.getBatch())));
        for (List<OpenApiOrderItem> sameGroupItems : grouped.values()) {
            sameGroupItems.sort(Comparator.comparing(OpenApiOrderItem::getId));
            for (int i = 0; i < sameGroupItems.size(); i++) {
                OpenApiOrderItem item = sameGroupItems.get(i);
                OpenApiOrderItemMap map = new OpenApiOrderItemMap()
                        .setOrderId(order.getId())
                        .setOrderCode(order.getCode())
                        .setSourceItemId(item.getId())
                        .setSourceLineId(item.getPlatItemId())
                        .setMergeMatnrCode(defaultString(item.getMatnrCode()))
                        .setMergeBatch(defaultString(item.getBatch()))
                        .setSeqNo(i + 1)
                        .setSourceQty(defaultQty(item.getAnfme()))
                        .setAllocatedQty(ZERO)
                        .setReportedQty(ZERO)
                        .setStatus(1)
                        .setDeleted(0);
                openApiOrderItemMapMapper.insert(map);
            }
        }
    }
    private Order buildMergedOrder(Order source) {
        Order merged = new Order()
                .setOrderNo(source.getOrderNo())
                .setOrderInternalCode(source.getOrderInternalCode())
                .setWkType(source.getWkType())
                .setCreateTime(source.getCreateTime())
                .setBusinessTime(source.getBusinessTime())
                .setStockDirect(source.getStockDirect())
                .setStationId(source.getStationId())
                .setCustomerId(source.getCustomerId())
                .setCustomerName(source.getCustomerName())
                .setSupplierId(source.getSupplierId())
                .setSupplierName(source.getSupplierName())
                .setStockOrgId(source.getStockOrgId())
                .setStockOrgName(source.getStockOrgName())
                .setPurchaseOrgId(source.getPurchaseOrgId())
                .setPurchaseOrgName(source.getPurchaseOrgName())
                .setPurchaseUserId(source.getPurchaseUserId())
                .setPurchaseUserName(source.getPurchaseUserName())
                .setPrdOrgId(source.getPrdOrgId())
                .setPrdOrgName(source.getPrdOrgName())
                .setSaleOrgId(source.getSaleOrgId())
                .setSaleOrgName(source.getSaleOrgName())
                .setSaleUserId(source.getSaleUserId())
                .setSaleUserName(source.getSaleUserName());
        merged.setType(source.getType());
        Map<String, List<OrderItem>> grouped = source.getOrderItems().stream().collect(Collectors.groupingBy(i -> mergeKey(i.getMatNr(), i.getBatch())));
        List<OrderItem> mergedItems = new ArrayList<>();
        int idx = 1;
        for (List<OrderItem> groupItems : grouped.values()) {
            OrderItem first = groupItems.get(0);
            BigDecimal qty = groupItems.stream()
                    .map(i -> toDecimal(i.getAnfme()))
                    .reduce(ZERO, BigDecimal::add)
                    .setScale(2, RoundingMode.HALF_UP);
            OrderItem mergedItem = new OrderItem()
                    .setLineId("M" + idx++)
                    .setPlanNo(first.getPlanNo())
                    .setMatNr(first.getMatNr())
                    .setMakTx(first.getMakTx())
                    .setModel(first.getModel())
                    .setAnfme(qty.doubleValue())
                    .setBatch(first.getBatch())
                    .setUnit(first.getUnit())
                    .setBaseUnit(first.getBaseUnit())
                    .setPriceUnitId(first.getPriceUnitId())
                    .setPalletId(first.getPalletId())
                    .setTargetWarehouseId(first.getTargetWarehouseId())
                    .setSourceWarehouseId(first.getSourceWarehouseId())
                    .setInStockType(first.getInStockType())
                    .setOwnerTypeId(first.getOwnerTypeId())
                    .setOwnerId(first.getOwnerId())
                    .setOwnerName(first.getOwnerName())
                    .setKeeperTypeId(first.getKeeperTypeId())
                    .setKeeperId(first.getKeeperId())
                    .setKeeperName(first.getKeeperName())
                    .setMemo(first.getMemo())
                    .setUseOrgId(first.getUseOrgId())
                    .setUseOrgName(first.getUseOrgName())
                    .setErpClsId(first.getErpClsId());
            mergedItem.setSpec(first.getSpec());
            mergedItems.add(mergedItem);
        }
        merged.setOrderItems(mergedItems);
        return merged;
    }
    private boolean existsReportEvent(String eventId, String taskNo, String reportNo) {
        return openApiOrderReportEventMapper.selectCount(new LambdaQueryWrapper<OpenApiOrderReportEvent>()
                .eq(OpenApiOrderReportEvent::getEventId, defaultString(eventId))
                .eq(OpenApiOrderReportEvent::getTaskNo, defaultString(taskNo))
                .eq(OpenApiOrderReportEvent::getReportNo, defaultString(reportNo))
                .eq(OpenApiOrderReportEvent::getStatus, 1)) > 0;
    }
    private OpenApiOrderReportEvent saveReportEvent(String eventId, String taskNo, String reportNo, String orderCode, String payload) {
        OpenApiOrderReportEvent event = new OpenApiOrderReportEvent()
                .setEventId(defaultString(eventId))
                .setTaskNo(defaultString(taskNo))
                .setReportNo(defaultString(reportNo))
                .setOrderCode(orderCode)
                .setPayload(payload)
                .setStatus(0);
        openApiOrderReportEventMapper.insert(event);
        return event;
    }
    private int allocateMergedDoneQty(String orderNo, String matnrCode, String batch, BigDecimal mergedDoneQty) {
        OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>()
                .eq(OpenApiOrder::getCode, orderNo)
                .last("limit 1"));
        if (Objects.isNull(order)) {
            throw new CoolException("未找到订单:" + orderNo);
        }
        LambdaQueryWrapper<OpenApiOrderItemMap> queryWrapper = new LambdaQueryWrapper<OpenApiOrderItemMap>()
                .eq(OpenApiOrderItemMap::getOrderId, order.getId())
                .eq(OpenApiOrderItemMap::getMergeMatnrCode, defaultString(matnrCode))
                .orderByAsc(OpenApiOrderItemMap::getSeqNo)
                .orderByAsc(OpenApiOrderItemMap::getId);
        if (StringUtils.isNotBlank(batch)) {
            queryWrapper.eq(OpenApiOrderItemMap::getMergeBatch, batch);
        }
        List<OpenApiOrderItemMap> mappingRows = openApiOrderItemMapMapper.selectList(queryWrapper);
        if (mappingRows.isEmpty()) {
            throw new CoolException("未找到映射关系,订单:" + orderNo + ",物料:" + matnrCode);
        }
        BigDecimal remaining = mergedDoneQty;
        int allocateRows = 0;
        for (OpenApiOrderItemMap row : mappingRows) {
            if (remaining.compareTo(ZERO) <= 0) {
                break;
            }
            BigDecimal sourceQty = defaultQty(row.getSourceQty());
            BigDecimal allocatedQty = defaultQty(row.getAllocatedQty());
            BigDecimal canAllocate = sourceQty.subtract(allocatedQty);
            if (canAllocate.compareTo(ZERO) <= 0) {
                continue;
            }
            BigDecimal toAllocate = remaining.min(canAllocate).setScale(2, RoundingMode.HALF_UP);
            if (toAllocate.compareTo(ZERO) <= 0) {
                continue;
            }
            row.setAllocatedQty(allocatedQty.add(toAllocate).setScale(2, RoundingMode.HALF_UP));
            openApiOrderItemMapMapper.updateById(row);
            openApiOrderItemMapper.update(null, new LambdaUpdateWrapper<OpenApiOrderItem>()
                    .eq(OpenApiOrderItem::getId, row.getSourceItemId())
                    .setSql("qty = IFNULL(qty,0) + " + toAllocate));
            remaining = remaining.subtract(toAllocate).setScale(2, RoundingMode.HALF_UP);
            allocateRows++;
        }
        if (remaining.compareTo(ZERO) > 0) {
            log.warn("回传数量超过未分配数量,orderNo={}, matnr={}, batch={}, overflow={}", orderNo, matnrCode, batch, remaining);
        }
        return allocateRows;
    }
    private int reportReadyLinesToErp(String orderNo) {
        OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>()
                .eq(OpenApiOrder::getCode, orderNo)
                .last("limit 1"));
        if (Objects.isNull(order)) {
            return 0;
        }
        List<OpenApiOrderItemMap> mappings = openApiOrderItemMapMapper.selectList(new LambdaQueryWrapper<OpenApiOrderItemMap>()
                .eq(OpenApiOrderItemMap::getOrderId, order.getId())
                .orderByAsc(OpenApiOrderItemMap::getSeqNo)
                .orderByAsc(OpenApiOrderItemMap::getId));
        int successCount = 0;
        for (OpenApiOrderItemMap mapping : mappings) {
            BigDecimal allocatedQty = defaultQty(mapping.getAllocatedQty());
            BigDecimal reportedQty = defaultQty(mapping.getReportedQty());
            BigDecimal delta = allocatedQty.subtract(reportedQty).setScale(2, RoundingMode.HALF_UP);
            if (delta.compareTo(ZERO) <= 0) {
                continue;
            }
            OpenApiOrderItem item = openApiOrderItemMapper.selectById(mapping.getSourceItemId());
            if (Objects.isNull(item)) {
                continue;
            }
            ReportParams params = buildLineReportParams(order, item, delta);
            CommonResponse erpResp = wmsErpService.reportOrders(params);
            if (Objects.nonNull(erpResp) && Objects.equals(erpResp.getCode(), 200)) {
                mapping.setReportedQty(reportedQty.add(delta).setScale(2, RoundingMode.HALF_UP));
                openApiOrderItemMapMapper.updateById(mapping);
                successCount++;
            } else {
                String msg = Objects.isNull(erpResp) ? "ERP响应为空" : erpResp.getMsg();
                log.warn("ERP行上报失败,orderNo={}, itemId={}, msg={}", orderNo, item.getId(), msg);
            }
        }
        return successCount;
    }
    private ReportParams buildLineReportParams(OpenApiOrder order, OpenApiOrderItem item, BigDecimal deltaQty) {
        ReportDataParam dataParam = new ReportDataParam()
                .setWMSNO(order.getCode())
                .setPONO(order.getPoCode())
                .setOrderNO(item.getPlatWorkCode())
                .setGoodsNO(item.getBatch())
                .setItemCode(item.getMatnrCode())
                .setEditUser("open-api")
                .setEditDate(new Date())
                .setMemoDtl("lineId=" + defaultString(item.getPlatItemId()));
        if ("in".equalsIgnoreCase(order.getType())) {
            dataParam.setInQty(deltaQty.doubleValue());
        } else {
            dataParam.setOutQty(deltaQty.doubleValue());
        }
        return new ReportParams().setOrderType(order.getType()).setAction("Update").setData(Collections.singletonList(dataParam));
    }
    private void refreshOrderFinishStatus(String orderNo) {
        OpenApiOrder order = openApiOrderMapper.selectOne(new LambdaQueryWrapper<OpenApiOrder>()
                .eq(OpenApiOrder::getCode, orderNo)
                .last("limit 1"));
        if (Objects.isNull(order)) {
            return;
        }
        List<OpenApiOrderItem> items = openApiOrderItemMapper.selectList(new LambdaQueryWrapper<OpenApiOrderItem>()
                .eq(OpenApiOrderItem::getOrderId, order.getId()));
        BigDecimal totalPlan = items.stream().map(i -> defaultQty(i.getAnfme())).reduce(ZERO, BigDecimal::add);
        BigDecimal totalDone = items.stream().map(i -> defaultQty(i.getQty())).reduce(ZERO, BigDecimal::add);
        int exceStatus = 0;
        if (totalDone.compareTo(ZERO) > 0 && totalDone.compareTo(totalPlan) < 0) {
            exceStatus = 1;
        } else if (totalDone.compareTo(totalPlan) >= 0 && totalPlan.compareTo(ZERO) > 0) {
            exceStatus = 2;
        }
        order.setQty(totalDone.setScale(2, RoundingMode.HALF_UP))
                .setWorkQty(totalDone.setScale(2, RoundingMode.HALF_UP))
                .setExceStatus(exceStatus);
        openApiOrderMapper.updateById(order);
    }
    private BigDecimal sumOrderItemQty(List<OrderItem> orderItems) {
        return orderItems.stream()
                .filter(Objects::nonNull)
                .map(i -> toDecimal(i.getAnfme()))
                .reduce(ZERO, BigDecimal::add)
                .setScale(2, RoundingMode.HALF_UP);
    }
    private BigDecimal toDecimal(Double value) {
        if (Objects.isNull(value)) {
            return ZERO;
        }
        return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP);
    }
    private BigDecimal defaultQty(BigDecimal value) {
        return Objects.isNull(value) ? ZERO : value.setScale(2, RoundingMode.HALF_UP);
    }
    private Date toDate(Long timestampSeconds) {
        if (Objects.isNull(timestampSeconds) || timestampSeconds <= 0L) {
            return null;
        }
        return new Date(timestampSeconds * 1000);
    }
    private String mergeKey(String matnr, String batch) {
        return defaultString(matnr) + "@@" + defaultString(batch);
    }
    private String defaultString(String value) {
        return StringUtils.trimToEmpty(value);
    }
    private String pickString(JSONObject object, String... candidates) {
        if (Objects.isNull(object) || Objects.isNull(candidates)) {
            return "";
        }
        for (String key : candidates) {
            Object value = object.get(key);
            if (Objects.nonNull(value) && StringUtils.isNotBlank(String.valueOf(value))) {
                return String.valueOf(value).trim();
            }
        }
        return "";
    }
    private JSONArray pickArray(JSONObject object, String... candidates) {
        if (Objects.isNull(object) || Objects.isNull(candidates)) {
            return new JSONArray();
        }
        for (String key : candidates) {
            Object value = object.get(key);
            if (value instanceof JSONArray) {
                return (JSONArray) value;
            }
            if (value instanceof List) {
                return JSONArray.parseArray(JSON.toJSONString(value));
            }
            if (value instanceof String && ((String) value).trim().startsWith("[")) {
                return JSONArray.parseArray((String) value);
            }
        }
        return new JSONArray();
    }
    private BigDecimal pickDecimal(JSONObject object, String... candidates) {
        if (Objects.isNull(object) || Objects.isNull(candidates)) {
            return ZERO;
        }
        for (String key : candidates) {
            Object value = object.get(key);
            if (Objects.isNull(value)) {
                continue;
            }
            try {
                return new BigDecimal(String.valueOf(value)).abs().setScale(2, RoundingMode.HALF_UP);
            } catch (Exception ignore) {
                // ignore invalid value
            }
        }
        return ZERO;
    }
    public static Map<String, Object> objectToMap(Object obj) {
        Map<String, Object> map = new HashMap<>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true); // 设置私有字段也可以访问
            try {
                map.put(field.getName(), field.get(obj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
    // 入/出库任务完成上报
    /**
     * 入/出库任务完成上报
     *
     * @param params
     * @return
     */
    public CommonResponse reportInOrOutBound(Object params) {
        if (Objects.isNull(params)) {
            throw new CoolException("入/出库任务信息参数不能为空!!");
@@ -64,29 +949,172 @@
        // TODO:参数转换
        ErpReportParams erpReportParams = new ErpReportParams();
        erpReportParams = (ErpReportParams) params;
        String erpUrl = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc";
        log.info("Erp入/出库任务完成上报: {}, 请求参数: {}", erpUrl, JSONObject.toJSONString(erpReportParams));
        try {
            JSONObject jsonObject = postRequest(erpUrl, erpReportParams, true);
            boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess");
            // TODO:转换后返回
            if (sendSuccess) {
                return CommonResponse.ok();
            } else {
                JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors");
                String errorMsg = "";
                for (int i = 0; i < errors.size(); i++) {
                    errorMsg += errors.getJSONObject(i).getString("Message") + " ";
        if (params instanceof ErpReportParams) {
            erpReportParams = (ErpReportParams) params;
        } else if (params instanceof java.util.Map) {
            java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params;
            // 设置基本属性
            erpReportParams.setFDate((String) paramMap.get("FDate"));
            erpReportParams.setF_OHDL_BillnoType((String) paramMap.get("F_OHDL_BillnoType"));
            erpReportParams.setFStockOrgId(paramMap.get("FStockOrgId"));
            erpReportParams.setFPrdOrgId(paramMap.get("FPrdOrgId"));
            erpReportParams.setF_OHDL_ProPlan((String) paramMap.get("F_OHDL_ProPlan"));
            // 处理FEntity列表
            Object fEntityObj = paramMap.get("FEntity");
            if (fEntityObj instanceof java.util.List) {
                java.util.List<?> fEntityList = (java.util.List<?>) fEntityObj;
                java.util.List<ErpReportParams.FEntityItem> entityItems = new java.util.ArrayList<>();
                for (Object item : fEntityList) {
                    if (item instanceof java.util.Map) {
                        java.util.Map<String, Object> itemMap = (java.util.Map<String, Object>) item;
                        ErpReportParams.FEntityItem entityItem = new ErpReportParams.FEntityItem();
                        // 使用反射设置属性值
                        try {
                            // 使用反射直接访问字段并设置值
                            java.lang.reflect.Field field;
                            field = entityItem.getClass().getDeclaredField("FMaterialId");
                            field.setAccessible(true);
                            field.set(entityItem, itemMap.get("FMaterialId"));
                            field = entityItem.getClass().getDeclaredField("FUnitID");
                            field.setAccessible(true);
                            field.set(entityItem, itemMap.get("FUnitID"));
                            // 处理数值类型
                            Object fAppQty = itemMap.get("FAppQty");
                            if (fAppQty instanceof Number) {
                                field = entityItem.getClass().getDeclaredField("FAppQty");
                                field.setAccessible(true);
                                field.set(entityItem, ((Number) fAppQty).doubleValue());
                            } else if (fAppQty != null) {
                                field = entityItem.getClass().getDeclaredField("FAppQty");
                                field.setAccessible(true);
                                field.set(entityItem, Double.parseDouble(fAppQty.toString()));
                            }
                            Object fActualQty = itemMap.get("FActualQty");
                            if (fActualQty instanceof Number) {
                                field = entityItem.getClass().getDeclaredField("FActualQty");
                                field.setAccessible(true);
                                field.set(entityItem, ((Number) fActualQty).doubleValue());
                            } else if (fActualQty != null) {
                                field = entityItem.getClass().getDeclaredField("FActualQty");
                                field.setAccessible(true);
                                field.set(entityItem, Double.parseDouble(fActualQty.toString()));
                            }
                            field = entityItem.getClass().getDeclaredField("FStockId");
                            field.setAccessible(true);
                            field.set(entityItem, itemMap.get("FStockId"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_BworkShop");
                            field.setAccessible(true);
                            field.set(entityItem, itemMap.get("F_OHDL_BworkShop"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_Pallet");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_Pallet"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_ConPoint");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_ConPoint"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_PlanNo");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_PlanNo"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_MONo");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_MONo"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_MOId");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_MOId"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_MOLine");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_MOLine"));
                            field = entityItem.getClass().getDeclaredField("F_OHDL_MOLineId");
                            field.setAccessible(true);
                            field.set(entityItem, (String) itemMap.get("F_OHDL_MOLineId"));
                        } catch (Exception e) {
                            log.error("设置FEntityItem属性时发生错误: " + e.getMessage());
                            throw new CoolException("设置FEntityItem属性失败: " + e.getMessage());
                        }
                        entityItems.add(entityItem);
                    } else if (item instanceof ErpReportParams.FEntityItem) {
                        entityItems.add((ErpReportParams.FEntityItem) item);
                    }
                }
                return CommonResponse.error(errorMsg);
                erpReportParams.setFEntity(entityItems);
            }
        } else {
            throw new CoolException("无法处理的参数类型: " + params.getClass().getName());
        }
        JSONObject model = new JSONObject();
        model.put("Model", erpReportParams);
        JSONObject data = new JSONObject();
        data.put("data", model);
        data.put("formid", "ke3d5adc0bbe64eceafd5891400adf40e");
        try {
            JSONObject loginResult = loginBySign();
            if (loginResult.getInteger("LoginResultType") == 1) {
                String erpUrl = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc";
                log.info("Erp入/出库任务完成上报: {}, 请求参数: {}", erpUrl, JSONObject.toJSONString(data));
                String result2 = httpPostExample(erpUrl, data.toJSONString());
                JSONObject jsonObject = JSONObject.parseObject(result2);
                log.info("Erp入/出库任务完成上报返回" + jsonObject.toJSONString());
                boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess");
                // TODO:转换后返回
                if (sendSuccess) {
                    return CommonResponse.ok();
                } else {
                    JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors");
                    String errorMsg = "";
                    for (int i = 0; i < errors.size(); i++) {
                        errorMsg += errors.getJSONObject(i).getString("Message") + " ";
                    }
                    return CommonResponse.error(errorMsg);
                }
            }
        } catch (Exception e) {
            log.error("Erp入/出库任务上报响应失败", e);
            throw new CoolException("Erp解析响应失败:" + e.getMessage());
            log.error("loginBySign", e);
        }
//        try {
//            JSONObject jsonObject = postRequest(erpUrl, data, true);
//            log.info(jsonObject.toJSONString());
//            boolean sendSuccess = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getBoolean("IsSuccess");
//
//            // TODO:转换后返回
//            if (sendSuccess) {
//                return CommonResponse.ok();
//            } else {
//                JSONArray errors = jsonObject.getJSONObject("Result").getJSONObject("ResponseStatus").getJSONArray("Errors");
//                String errorMsg = "";
//                for (int i = 0; i < errors.size(); i++) {
//                    errorMsg += errors.getJSONObject(i).getString("Message") + " ";
//                }
//                return CommonResponse.error(errorMsg);
//            }
//        } catch (Exception e) {
//            log.error("Erp入/出库任务上报响应失败", e);
//            throw new CoolException("Erp解析响应失败:" + e.getMessage());
//        }
        return null;
    }
@@ -96,10 +1124,28 @@
    // 盘点结果上报
    // region 登录
    /**
     * 登录,登录参数依次为账套ID、用户名、应用ID、时间戳、签名信息、语言ID
     *
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    public JSONObject loginBySign() throws UnsupportedEncodingException, NoSuchAlgorithmException {
        String url = ERP_REPORT_URL + "/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginBySign.common.kdsvc";
        JSONObject params = new JSONObject();
        params.put("parameters", loginParams());
        String result = httpPostExample(url, params.toJSONString());
        return JSONObject.parseObject(result);
    }
    /**
     * 登录参数整理
     *
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    private Object[] loginParams() throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //时间戳
        long timestamp = System.currentTimeMillis() / 1000;
@@ -137,16 +1183,16 @@
        }
        return hashString.toString();
    }
    // endregion
    /**
     * 通用HTTP POST请求方法
     *
     * @param url 请求URL
     * @param params 请求参数
     * @param needToken 是否需要token认证
     * @return 响应结果
     */
    public JSONObject postRequest(String url, Object params, boolean needToken) {
    public JSONObject postRequest(String url, Object params) {
        if (StringUtils.isBlank(url)) {
            throw new CoolException("请求URL不能为空!!");
        }
@@ -159,13 +1205,21 @@
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json;charset=utf-8");
        if (needToken) {
//            String token = getToken();
//            headers.add("Authorization", "Bearer " + token);
        }
        HttpEntity<Object> httpEntity = new HttpEntity<>(params, headers);
        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
        // 创建支持忽略SSL证书验证的RestTemplate
        RestTemplate sslRestTemplate = SslUtils.createIgnoreSSLRestTemplate();
        // 设置错误处理器,不抛出异常,而是返回响应体
        sslRestTemplate.setErrorHandler(new org.springframework.web.client.DefaultResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse response) throws IOException {
                // 不管状态码如何,都不视为错误
                return false;
            }
        });
        ResponseEntity<String> exchange = sslRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
        log.info("Erp POST请求响应结果: {}", exchange);
        if (Objects.isNull(exchange.getBody())) {
@@ -181,4 +1235,143 @@
            throw new CoolException("Erp解析响应失败:" + e.getMessage());
        }
    }
    /**
     * HTTP POST请求示例 - 支持HTTPS
     *
     * @param url    请求URL
     * @param params 请求参数
     * @return 响应结果
     */
    public String httpPostExample(String url, String params) {
        if (httpClient == null) {
            httpClient = createHttpsClient();
        }
        HttpPost httpPost = new HttpPost(url);
        try {
            StringEntity entity = new StringEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            httpPost.setHeader("Content-type", "application/json;charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            return EntityUtils.toString(httpClient.execute(httpPost).getEntity());
        } catch (Exception e) {
            log.error("HTTP POST请求失败: {}", e.getMessage(), e);
            throw new CoolException("HTTP POST请求失败: " + e.getMessage());
        }
    }
    /**
     * 使用RestTemplate的HTTPS POST请求示例
     *
     * @param url    请求URL
     * @param params 请求参数
     * @return 响应结果
     */
    public String httpsPostWithRestTemplate(String url, String params) {
        try {
            log.info("HTTPS POST请求: {}, 请求参数: {}", url, params);
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/json;charset=utf-8");
            headers.add("Accept", "application/json");
            HttpEntity<String> httpEntity = new HttpEntity<>(params, headers);
            // 使用项目中已有的SSL工具类创建忽略SSL证书验证的RestTemplate
            RestTemplate sslRestTemplate = SslUtils.createIgnoreSSLRestTemplate();
            // 设置错误处理器,不抛出异常,而是返回响应体
            sslRestTemplate.setErrorHandler(new org.springframework.web.client.DefaultResponseErrorHandler() {
                @Override
                public boolean hasError(ClientHttpResponse response) throws IOException {
                    // 不管状态码如何,都不视为错误
                    return false;
                }
            });
            ResponseEntity<String> exchange = sslRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
            log.info("HTTPS POST请求响应结果: {}", exchange);
            if (Objects.isNull(exchange.getBody())) {
                throw new CoolException("请求失败!!");
            }
            return exchange.getBody();
        } catch (Exception e) {
            log.error("HTTPS POST请求失败: {}", e.getMessage(), e);
            throw new CoolException("HTTPS POST请求失败: " + e.getMessage());
        }
    }
    /**
     * 创建支持HTTPS的HttpClient
     *
     * @return CloseableHttpClient实例
     */
    private CloseableHttpClient createHttpsClient() {
        try {
            // 创建信任所有证书的TrustManager
            TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() { return null; }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) { }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) { }
                }
            };
            // 初始化SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // 创建SSL连接管理器
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext,
                    (hostname, session) -> true // 允许所有主机名
            );
            // 创建HttpClientBuilder并设置SSL配置
            RequestConfig config = RequestConfig.custom()
                    .setConnectTimeout(30000)  // 连接超时时间
                    .setSocketTimeout(60000)   // 读取超时时间
                    .build();
            return HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .setDefaultRequestConfig(config)
                    .build();
        } catch (Exception e) {
            log.error("创建HTTPS客户端失败: {}", e.getMessage(), e);
            return HttpClients.createDefault(); // 回退到默认客户端
        }
    }
//    /**
//     * 示例:如何使用HTTPS POST方法
//     *
//     * @param url    目标URL
//     * @param jsonData JSON数据
//     * @return 响应结果
//     */
//    public String exampleUsage(String url, String jsonData) {
//        log.info("开始调用HTTPS POST请求示例");
//
//        try {
//            // 方法1: 使用Apache HttpClient
//            String result1 = httpPostExample(url, jsonData);
//            log.info("使用HttpClient的POST请求结果: {}", result1);
//
//            // 方法2: 使用RestTemplate
//            String result2 = httpsPostWithRestTemplate(url, jsonData);
//            log.info("使用RestTemplate的POST请求结果: {}", result2);
//
//            // 根据实际需要选择返回结果
//            return result1;
//        } catch (Exception e) {
//            log.error("HTTPS POST请求示例执行失败: {}", e.getMessage(), e);
//            throw e;
//        }
//    }
}