| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.web.client.RestTemplate; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | |
| | | /** |
| | | * 应收账单Service业务层处理 |
| | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 更新推送状态 |
| | | * |
| | |
| | | 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()); |
| | |
| | | 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 |
| | |
| | | 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; |
| | |
| | | createTitleArea(sheet, styles,bill); |
| | | |
| | | // 表头 |
| | | createDynamicTableHeader(sheet, styles, feeNameList, baseColumns, remarkColumn); |
| | | createDynamicTableHeader(sheet, styles, feeNameList, feeCurrencyMap, baseColumns, remarkColumn); |
| | | |
| | | // 数据区域 |
| | | int startRow = 5; |
| | |
| | | }}); |
| | | // 处理应收费用明细 |
| | | 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()); |
| | | } |
| | | |
| | | // 填充费用列 |
| | |
| | | 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++; |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | * |
| | | * @param sheet 工作表 |
| | | * @param styles 样式映射 |
| | | * @param tmsReceivableFee 应收费用查询条件 |
| | | */ |
| | | private void createTitleArea(SXSSFSheet sheet, Map<String, CellStyle> styles, TmsArBill tmsArBill) { |
| | | // 标题行(无边框,居中) |
| | |
| | | * @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); |
| | | |
| | |
| | | // 费用列 |
| | | 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")); |
| | | } |
| | | |