sen
2 天以前 5abcde36961125cbf436f91b8c17610a6b5f8308
tms/src/main/java/com/ruoyi/tms/service/impl/TmsArBillServiceImpl.java
@@ -1,7 +1,5 @@
package com.ruoyi.tms.service.impl;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
@@ -23,6 +21,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@@ -47,6 +46,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
/**
 * 应收账单Service业务层处理
@@ -291,6 +291,69 @@
        executor.execute(() -> pushToExternalSystem(tmsArBill, tmsReceivableFees));
    }
    @Override
    public void cancelPushToExternalSystem(Integer id) {
        TmsArBill tmsArBill = tmsArBillMapper.selectTmsArBillById(id);
        if (tmsArBill == null) {
            throw new RuntimeException("应收账单不存在");
        }
        // 异步推送作废请求
        AsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
        executor.execute(() -> pushCancelToExternalSystem(tmsArBill));
    }
    /**
     * 向外部系统推送应收数据作废
     * @param tmsArBill 应收账单
     */
    @Async
    protected void pushCancelToExternalSystem(TmsArBill tmsArBill) {
        java.util.Map<String, Object> requestBody = new java.util.HashMap<>();
        try {
    ;
            // 构建请求体
            String apiUrl = url+"/cancelBill";
            // 构建请求体,只需要sourceSystemId
            requestBody.put("sourceSystemId", tmsArBill.getSourceSystemId());
            // 设置HTTP头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(requestBody), headers);
            // 发送API请求
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.POST, entity, String.class);
            logger.info("推送应收数据作废到外部系统成功,响应: {}", response.getBody());
            // 更新推送状态为成功
            tmsArBill.setStatus(3); // 设置账单状态为作废
            tmsArBillMapper.updateTmsArBill(tmsArBill);
            // 重置关联的应收费用状态为待确认
            tmsReceivableFeeMapper.update(new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<TmsReceivableFee>()
                    .set(TmsReceivableFee::getStatus, 0)
                    .set(TmsReceivableFee::getBillRelationId, null)
                    .set(TmsReceivableFee::getBillRelationNo, null)
                    .eq(TmsReceivableFee::getBillRelationId, tmsArBill.getId())
            );
            logger.info("重置应收费用状态成功,账单ID: {}", tmsArBill.getId());
        } catch (Exception e) {
            logger.error("推送应收数据作废到外部系统失败,账单ID: {}, 客户: {}",
                tmsArBill.getId(), tmsArBill.getCustomerName(), e);
            logger.debug("推送失败的请求数据: {}", JSON.toJSONString(requestBody));
            // 更新推送状态为失败
            tmsArBill.setPushStatus(3);
            tmsArBill.setPushTime(DateUtils.getNowDate());
            tmsArBillMapper.updateTmsArBill(tmsArBill);
        }
    }
    /**
     * 更新推送状态
     *
@@ -430,6 +493,17 @@
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.POST, entity, String.class);
            logger.info("推送数据到外部系统成功,响应: {}", response.getBody());
            // 解析响应,获取sourceSystemId
            try {
                JSONObject result = JSONObject.parseObject(response.getBody());
                String sourceSystemId = result.getString("sourceSystemId");
                if (sourceSystemId != null) {
                    tmsArBill.setSourceSystemId(Integer.parseInt(sourceSystemId));
                }
            } catch (Exception e) {
                logger.error("解析外部系统响应失败: {}", e.getMessage());
            }
            // 更新推送状态为成功
            tmsArBill.setPushStatus(2);
            tmsArBill.setPushTime(DateUtils.getNowDate());
@@ -497,8 +571,8 @@
            String rateStr = sysConfigService.selectConfigByKey("sys.hk.rmb.rate");
            BigDecimal exchangeRate = new BigDecimal(rateStr);
            
            // 收集所有费用名称,用于动态生成列
            Set<String> feeNames = new HashSet<>();
            // 收集所有费用名称和对应的货币,用于动态生成列
            Map<String, String> feeCurrencyMap = new HashMap<>();
                for (TmsArBillItem item : bill.getItems()) {
                    // 应收费用ID
@@ -507,15 +581,33 @@
                    List<TmsReceivableFeeItem> tmsReceivableFeeItems = tmsReceivableFeeItemMapper.selectTmsReceivableFeeItemList(new TmsReceivableFeeItem() {{
                        setHeadId(arFeeId);
                    }});
                    // 从应收费用明细中收集费用名称
                    // 从应收费用明细中收集费用名称和货币
                    for (TmsReceivableFeeItem feeItem : tmsReceivableFeeItems) {
                        feeNames.add(feeItem.getFeeName());
                        feeCurrencyMap.put(feeItem.getFeeName(), feeItem.getCurrency());
                    }
                }
            
            // 将费用名称转换为列表,保持顺序
            List<String> feeNameList = new ArrayList<>(feeNames);
            // 将费用名称转换为列表,并按要求排序:运费放在最前面,杂费放在最后面
            List<String> feeNameList = new ArrayList<>();
            List<String> otherFees = new ArrayList<>();
            for (String feeName : feeCurrencyMap.keySet()) {
                if ("运费".equals(feeName)) {
                    feeNameList.add(feeName);
                } else if ("杂费".equals(feeName)) {
                    otherFees.add(feeName);
                } else {
                    otherFees.add(feeName);
                }
            }
            // 添加其他费用
            feeNameList.addAll(otherFees.stream().filter(fee -> !"杂费".equals(fee)).collect(Collectors.toList()));
            // 添加杂费到最后
            if (feeCurrencyMap.containsKey("杂费")) {
                feeNameList.add("杂费");
            }
            
            // 基础列数(序号、装货日期、装货点、卸货点、车牌、型号)
            int baseColumns = 6;
@@ -541,7 +633,7 @@
            createTitleArea(sheet, styles,bill);
            
            // 表头
            createDynamicTableHeader(sheet, styles, feeNameList, baseColumns, remarkColumn);
            createDynamicTableHeader(sheet, styles, feeNameList, feeCurrencyMap, baseColumns, remarkColumn);
            
            // 数据区域
            int startRow = 5;
@@ -614,12 +706,8 @@
                        }});
                        // 处理应收费用明细
                        for (TmsReceivableFeeItem feeItem : tmsReceivableFeeItems) {
                            BigDecimal amount = feeItem.getRegisterAmount();
                            // 如果是港币,转换为人民币
                            if ("HKD".equals(feeItem.getCurrency()) || "港币".equals(feeItem.getCurrency())) {
                                amount = amount.multiply(exchangeRate).setScale(2, RoundingMode.HALF_UP);
                            }
                            feeMap.put(feeItem.getFeeName(), amount);
                            // 保持原始金额,不进行币种转换
                            feeMap.put(feeItem.getFeeName(), feeItem.getRegisterAmount());
                        }
                        
                        // 填充费用列
@@ -634,9 +722,9 @@
                            feeTotals.put(feeName, feeTotals.get(feeName).add(feeAmount));
                        }
                        
                        // 备注
                        // 备注 - 为空
                        Cell remarkCell = row.createCell(remarkColumn);
                        remarkCell.setCellValue("" + (fee.getDispatchNo() != null ? fee.getDispatchNo() : ""));
                        remarkCell.setCellValue("");
                        remarkCell.setCellStyle(styles.get("data"));
                        
                        rowIndex++;
@@ -673,13 +761,24 @@
                if (i == 0) {
                    cell.setCellValue("合计(RMB)");
                }
                // 合计行的备注设置汇率
                if (i == remarkColumn) {
                    cell.setCellValue("汇率: " + exchangeRate);
                }
                cell.setCellStyle(styles.get("total"));
            }
            sheet.addMergedRegion(new CellRangeAddress(totalRow, totalRow, 0, 5));
            // 计算所有费用的合计
            // 计算所有费用的合计(转换为人民币)
            BigDecimal grandTotal = BigDecimal.ZERO;
            for (BigDecimal amount : feeTotals.values()) {
            for (String feeName : feeTotals.keySet()) {
                BigDecimal amount = feeTotals.get(feeName);
                // 获取该费用的币种
                String currency = feeCurrencyMap.get(feeName);
                // 如果是港币,转换为人民币
                if ("HKD".equals(currency) || "港币".equals(currency)) {
                    amount = amount.multiply(exchangeRate).setScale(2, RoundingMode.HALF_UP);
                }
                grandTotal = grandTotal.add(amount);
            }
            
@@ -825,7 +924,6 @@
     *
     * @param sheet 工作表
     * @param styles 样式映射
     * @param tmsReceivableFee 应收费用查询条件
     */
    private void createTitleArea(SXSSFSheet sheet, Map<String, CellStyle> styles, TmsArBill tmsArBill) {
        // 标题行(无边框,居中)
@@ -891,10 +989,11 @@
     * @param sheet 工作表
     * @param styles 样式映射
     * @param feeNameList 费用名称列表
     * @param feeCurrencyMap 费用名称到货币的映射
     * @param baseColumns 基础列数
     * @param remarkColumn 备注列位置
     */
    private void createDynamicTableHeader(SXSSFSheet sheet, Map<String, CellStyle> styles, List<String> feeNameList, int baseColumns, int remarkColumn) {
    private void createDynamicTableHeader(SXSSFSheet sheet, Map<String, CellStyle> styles, List<String> feeNameList, Map<String, String> feeCurrencyMap, int baseColumns, int remarkColumn) {
        Row headerRow = sheet.createRow(4);
        headerRow.setHeightInPoints(25);
        
@@ -909,7 +1008,10 @@
        // 费用列
        for (int i = 0; i < feeNameList.size(); i++) {
            Cell cell = headerRow.createCell(baseColumns + i);
            cell.setCellValue(feeNameList.get(i) + "(人民币)");
            String feeName = feeNameList.get(i);
            String currency = feeCurrencyMap.get(feeName);
            cell.setCellValue(feeName + "(" + currency + ")");
            cell.setCellStyle(styles.get("header"));
        }