Browse Source

Merge remote-tracking branch 'origin/master' into master

yangyj 1 year ago
parent
commit
bd7a53f033
17 changed files with 621 additions and 32 deletions
  1. 17 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialSummaryRecordDataJson.java
  2. 3 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/InventoryFormMeterVO.java
  3. 23 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterLinkWbsInfoVO.java
  4. 46 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterTreeContractVO2.java
  5. 26 0
      blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/WbsLinkQueryInfoVO.java
  6. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  7. 125 7
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialSummaryController.java
  8. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TrialSummaryClassificationConfigurationController.java
  9. 1 1
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java
  10. 27 14
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MidPayItemController.java
  11. 16 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MiddleMeterApplyController.java
  12. 1 1
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java
  13. 4 3
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.xml
  14. 11 4
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MiddleMeterApplyMapper.java
  15. 44 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MiddleMeterApplyMapper.xml
  16. 5 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/IMiddleMeterApplyService.java
  17. 269 0
      blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MiddleMeterApplyServiceImpl.java

+ 17 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/TrialSummaryRecordDataJson.java

@@ -0,0 +1,17 @@
+package org.springblade.business.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class TrialSummaryRecordDataJson implements Serializable {
+
+    private Long id;
+    private Long recordId;
+    private Long excelId;
+    private String jsonData;
+    private Date createTime;
+
+}

+ 3 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/InventoryFormMeterVO.java

@@ -37,6 +37,9 @@ public class InventoryFormMeterVO extends InventoryFormMeter {
 	@ApiModelProperty(value = "当前部位当前清单当前计量总和")
 	private BigDecimal allMeterMoney;
 
+	@ApiModelProperty(value = "当前部位当前清单当前计量数量总和")
+	private BigDecimal allMeterTotal;
+
 	@ApiModelProperty(value = "清单编号")
 	private String formNumber;
 

+ 23 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterLinkWbsInfoVO.java

@@ -0,0 +1,23 @@
+package org.springblade.meter.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @Param   计量单元关联的节点信息->附带节点状态,附带节点最大附件type
+ * @Author wangwl
+ * @Date 2024/3/13 14:02
+ **/
+@Data
+public class MeterLinkWbsInfoVO {
+
+    @ApiModelProperty(value = "wbs_contract 的pKeyId")
+    private Long id;
+
+    @ApiModelProperty(value = "节点审批状态")
+    private Integer appStatus;
+
+    @ApiModelProperty(value = "节点最大附件type值")
+    private Integer maxType;
+
+}

+ 46 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/MeterTreeContractVO2.java

@@ -0,0 +1,46 @@
+package org.springblade.meter.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springblade.meter.entity.MeterTreeContract;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 自动计量专用VO
+ */
+@Data
+public class MeterTreeContractVO2 {
+
+    @ApiModelProperty(value = "合同计量单元id")
+    private Long id;
+
+    @ApiModelProperty(value = "合同计量单元名称")
+    private String nodeName;
+
+    @ApiModelProperty(value = "是否混泥土节点1是0否")
+    private Integer isConcreteNode;
+
+    @ApiModelProperty(value = "7天强度")
+    private BigDecimal sevenRatio;
+
+    @ApiModelProperty(value = "28天强度")
+    private BigDecimal twentyEightRatio;
+
+    @ApiModelProperty(value = "关联的WBS,逗号拼接")
+    private String linkWbs;
+
+    @ApiModelProperty(value = "关联的清单,逗号拼接")
+    private String linkForm;
+
+    @ApiModelProperty(value = "当前期的中间计量的id,逗号拼接")
+    private String linkMiddle;
+
+    @ApiModelProperty(value = "中期计量总体支付比例")
+    private BigDecimal payRatio;
+
+    @ApiModelProperty(value = "计算式")
+    private String calculateFormula;
+
+}

+ 26 - 0
blade-service-api/blade-meter-api/src/main/java/org/springblade/meter/vo/WbsLinkQueryInfoVO.java

@@ -0,0 +1,26 @@
+package org.springblade.meter.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @Param   WBS节点的审批信息-> 包含电签PDF和queryInfoId和name
+ * @Author wangwl
+ * @Date 2024/3/13 14:02
+ **/
+@Data
+public class WbsLinkQueryInfoVO {
+
+    @ApiModelProperty(value = "u_information_query的id")
+    private Long id;
+
+    @ApiModelProperty(value = "电签PDF")
+    private String eVisaPdf;
+
+    @ApiModelProperty(value = "wbs节点的pKeyId")
+    private Long wbsId;
+
+    @ApiModelProperty(value = "u_information_query的name")
+    private String name;
+
+}

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -1559,7 +1559,7 @@ public class TaskController extends BladeController {
                         for (TaskParallel taskPa : taskParallelList) {
                             if (taskPa.getStatus() == 2 && ObjectUtil.isNotEmpty(taskPa.getEVisaStatus()) && taskPa.getEVisaStatus() == 1) {
                                 taskPa.setEVisaStatus(2);
-                                if (taskPa.getEVisaContent().contains("请等待") && ObjectUtil.isEmpty(eVisaFailedInfo)) {
+                                if (StringUtils.isNotBlank(taskPa.getEVisaContent()) && taskPa.getEVisaContent().contains("请等待") && ObjectUtil.isEmpty(eVisaFailedInfo)) {
                                     eVisaFailedInfo = taskPa.getEVisaContent();
                                 }
                             } else if (taskPa.getStatus() == 3 && taskPa.getTaskUser().equals(SecureUtil.getUserId().toString())) {

+ 125 - 7
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialSummaryController.java

@@ -1,5 +1,7 @@
 package org.springblade.business.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -11,6 +13,7 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.StringUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -22,6 +25,7 @@ import org.springblade.business.dto.TrialSummaryRecordDTO;
 import org.springblade.business.dto.TrialSummaryRecordPageDTO;
 import org.springblade.business.entity.TrialSelfInspectionRecord;
 import org.springblade.business.entity.TrialSummaryRecord;
+import org.springblade.business.entity.TrialSummaryRecordDataJson;
 import org.springblade.business.service.impl.TrialSelfInspectionRecordServiceImpl;
 import org.springblade.business.service.impl.TrialSummaryRecordServiceImpl;
 import org.springblade.business.vo.TrialSummaryRecordVO;
@@ -29,6 +33,7 @@ import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.entity.ContractInfo;
@@ -641,14 +646,127 @@ public class TrialSummaryController {
         return R.status(trialSummaryRecordServiceImpl.deleteLogic(Func.toLongList(ids)));
     }
 
-    @PostMapping("/download")
+    @GetMapping("/download")
     @ApiOperationSupport(order = 5)
-    @ApiOperation(value = "下载", notes = "调page接口的pdfUrl下载")
-    public R<Object> download() {
-        /*如需下载excel,获取u_trial_summary_record_data_json表数据,解析json_data,根据classId获取分类配置的清表excel模板,插入excel对应位置。
-        json_data格式:{"2:2@9:9@pageSize@0": "AAA", .... };@pageSize@0表示第一个sheet;2:2@9:9表示位置信息,x1=2,x2=2;y1=9,y2=9 ;值=AAA。*/
-        //TODO
-        return R.success("操作成功");
+    @ApiOperation(value = "下载excel", notes = "传入记录的id,拼接成英文逗号分割的ids")
+    public R<Object> download(@RequestParam String ids) throws Exception {
+        if (StringUtils.isNotEmpty(ids)) {
+            List<TrialSummaryRecord> trialSummaryRecords = trialSummaryRecordServiceImpl.getBaseMapper().selectBatchIds(Func.toStrList(ids));
+            if (trialSummaryRecords.size() > 0) {
+                List<TrialSummaryRecordDataJson> query = jdbcTemplate.query("SELECT * FROM u_trial_summary_record_data_json WHERE record_id in(" + ids + ")", new BeanPropertyRowMapper<>(TrialSummaryRecordDataJson.class));
+                if (query.size() <= 0) {
+                    throw new ServiceException("未获取到数据信息");
+                }
+                Set<Long> excelIds = query.stream().map(TrialSummaryRecordDataJson::getExcelId).collect(Collectors.toSet());
+                Map<Long, TrialSummaryRecordDataJson> jsonMap = query.stream().collect(Collectors.toMap(TrialSummaryRecordDataJson::getRecordId, Function.identity()));
+                Map<Long, String> excelUrlMaps = jdbcTemplate.query("SELECT id,file_url FROM m_excel_tab WHERE id in(" + StringUtils.join(excelIds, ",") + ")", new BeanPropertyRowMapper<>(ExcelTab.class)).stream().collect(Collectors.toMap(ExcelTab::getId, ExcelTab::getFileUrl));
+
+                List<MultipartFile> files = new LinkedList<>();
+
+                for (TrialSummaryRecord record : trialSummaryRecords) {
+                    TrialSummaryRecordDataJson jsonData = jsonMap.getOrDefault(record.getId(), null);
+                    String excelUrl = excelUrlMaps.getOrDefault(jsonData.getExcelId(), null);
+                    if (StringUtils.isNotEmpty(excelUrl) && ObjectUtil.isNotEmpty(jsonData)) {
+
+                        String jsonStr = jsonData.getJsonData();
+                        JSONObject jsonObject = JSON.parseObject(jsonStr);
+                        @SuppressWarnings("unchecked")
+                        Map<String, String> map = jsonObject.toJavaObject(Map.class);
+
+                        Map<String, List<Map.Entry<String, String>>> groupedByPageSize = map.entrySet().stream()
+                                .collect(Collectors.groupingBy(entry -> {
+                                    String[] indexAndPageSize = entry.getKey().split("@pageSize@");
+                                    return indexAndPageSize[1];
+                                }));
+
+                        for (Map.Entry<String, List<Map.Entry<String, String>>> page : groupedByPageSize.entrySet()) {
+                            InputStream modInput = CommonUtil.getOSSInputStream(excelUrl);
+                            if (modInput != null) {
+                                try (Workbook workbook = new XSSFWorkbook(modInput)) {
+                                    Sheet sheet = workbook.getSheetAt(0);
+                                    for (Map.Entry<String, String> entry : page.getValue()) {
+                                        String key = entry.getKey();
+                                        String value = entry.getValue();
+                                        String[] indexAndPageSize = key.split("@pageSize@");
+
+                                        String index = indexAndPageSize[0];
+
+                                        String[] coordinates = index.split("@");
+                                        String x = coordinates[0];
+                                        String y = coordinates[1];
+
+                                        int x1 = Integer.parseInt(x.split(":")[0]) - 1;
+                                        int x2 = Integer.parseInt(x.split(":")[1]) - 1;
+                                        int y1 = Integer.parseInt(y.split(":")[0]) - 1;
+                                        int y2 = Integer.parseInt(y.split(":")[1]) - 1;
+
+                                        mergeAndCenterCells(sheet, x1, x2, y1, y2, value);
+                                    }
+
+                                    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+                                        workbook.write(byteArrayOutputStream);
+                                        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) {
+                                            files.add(new MockMultipartFile("file", excelUrl, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", byteArrayInputStream));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (files.size() > 0) {
+                    MultipartFile multipartFile = mergeExcelFiles(files);
+                    if (multipartFile != null) {
+                        BladeFile bladeFile = newIOSSClient.uploadFileByInputStream(multipartFile);
+                        if (bladeFile != null) {
+                            return R.data(bladeFile.getLink());
+                        }
+                    }
+                }
+            }
+        }
+        return R.fail("操作失败");
+    }
+
+    private MultipartFile mergeExcelFiles(List<MultipartFile> files) throws IOException {
+        Workbook mergedWorkbook = new XSSFWorkbook();
+        int sheetNumber = 1;
+        for (MultipartFile file : files) {
+            try (InputStream inputStream = file.getInputStream()) {
+                Workbook workbook = WorkbookFactory.create(inputStream);
+                int numberOfSheets = workbook.getNumberOfSheets();
+                for (int i = 0; i < numberOfSheets; i++) {
+                    Sheet sheet = workbook.getSheetAt(i);
+                    Sheet newSheet = mergedWorkbook.createSheet("Sheet" + sheetNumber++);
+                    copySheet(sheet, newSheet);
+                }
+            } catch (InvalidFormatException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        mergedWorkbook.write(outputStream);
+        return new MockMultipartFile("file", SnowFlakeUtil.getId() + "_file.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", outputStream.toByteArray());
+    }
+
+    private void copySheet(Sheet sourceSheet, Sheet targetSheet) {
+        int rowCount = sourceSheet.getLastRowNum();
+        for (int i = 0; i <= rowCount; i++) {
+            Row sourceRow = sourceSheet.getRow(i);
+            Row newRow = targetSheet.createRow(i);
+            if (sourceRow != null) {
+                int columnCount = sourceRow.getLastCellNum();
+                for (int j = 0; j < columnCount; j++) {
+                    Cell sourceCell = sourceRow.getCell(j);
+                    Cell newCell = newRow.createCell(j);
+                    if (sourceCell != null) {
+                        newCell.setCellValue(sourceCell.getStringCellValue());
+                    }
+                }
+            }
+        }
     }
 
 

+ 2 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TrialSummaryClassificationConfigurationController.java

@@ -295,7 +295,8 @@ public class TrialSummaryClassificationConfigurationController extends BladeCont
                         map.put("id", obj.getId());
                         map.put("trialTabId", obj.getTrialTabId());
                         map.put("elementId", obj.getElementId());
-                        map.put("elementValue", eleMap.getOrDefault(obj.getElementId(), null));
+                        WbsFormElement orDefault = eleMap.getOrDefault(obj.getElementId(), null);
+                        map.put("elementValue", ObjectUtil.isNotEmpty(orDefault) ? orDefault.getEName() : null);
                         map.put("htmlKeyName", obj.getHtmlKeyName());
                         maps.add(map);
                     }

+ 1 - 1
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MeterTreeController.java

@@ -905,7 +905,7 @@ public class MeterTreeController extends BladeController {
     @ApiOperation(value = "删除合同计量单元关联WBS节点", notes = "传入wbs节点ids,逗号拼接")
     public R<String> deleteLinkWbsTree(@RequestBody Map<String, String> params) {
         meterTreeContractService.deleteLinkWbsTree(params);
-        return R.success("删除成功");
+        return R.success("取消关联成功");
     }
 
 }

+ 27 - 14
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MidPayItemController.java

@@ -425,25 +425,38 @@ public class MidPayItemController extends BladeController {
         if (collect.size() > 0) {
             meterMidPayItemProjects = payItemProjectService.getBaseMapper().selectList(Wrappers.<MeterMidPayItemProject>lambdaQuery()
                     .eq(MeterMidPayItemProject::getProjectId, projectId)
-                    .notIn(MeterMidPayItemProject::getId, collect)
-                    .orderByAsc(MeterMidPayItemProject::getCreateTime));
+                    .notIn(MeterMidPayItemProject::getId, collect));
         } else {
             meterMidPayItemProjects = payItemProjectService.getBaseMapper().selectList(Wrappers.<MeterMidPayItemProject>lambdaQuery()
-                    .eq(MeterMidPayItemProject::getProjectId, projectId)
-                    .orderByAsc(MeterMidPayItemProject::getCreateTime));
+                    .eq(MeterMidPayItemProject::getProjectId, projectId));
         }
 
-        List<MeterMidPayItemProjectVO> VOS = BeanUtil.copyProperties(meterMidPayItemProjects, MeterMidPayItemProjectVO.class);
-        for (MeterMidPayItemProjectVO vo : VOS) {
-            if (ObjectUtil.isNotEmpty(vo.getPayApplicableType())) {
-                vo.setPayApplicableTypeName(meterPayAppTypeMap.getOrDefault(vo.getPayApplicableType().toString(), null));
-            }
-            if (ObjectUtil.isNotEmpty(vo.getPayType())) {
-                vo.setPayTypeName(meterPayTypeMap.getOrDefault(vo.getPayType().toString(), null));
-            }
-        }
+        List<MeterMidPayItemProjectVO> sortVOS = meterMidPayItemProjects.stream()
+                .map(project -> {
+                    MeterMidPayItemProjectVO vo = new MeterMidPayItemProjectVO();
+                    BeanUtil.copyProperties(project, vo);
+                    if (ObjectUtil.isNotEmpty(project.getPayApplicableType())) {
+                        vo.setPayApplicableTypeName(meterPayAppTypeMap.getOrDefault(project.getPayApplicableType().toString(), null));
+                    }
+                    if (ObjectUtil.isNotEmpty(project.getPayType())) {
+                        vo.setPayTypeName(meterPayTypeMap.getOrDefault(project.getPayType().toString(), null));
+                    }
+                    return vo;
+                }).sorted(
+                        Comparator.nullsLast(
+                                Comparator.<MeterMidPayItemProjectVO, Integer>comparing(
+                                        projectVO -> {
+                                            Integer sortValue = projectVO.getSort();
+                                            return sortValue != null ? sortValue : Integer.MAX_VALUE;
+                                        }
+                                )
+                        )
+                                .thenComparing(
+                                        Comparator.nullsLast(Comparator.comparing(MeterMidPayItemProjectVO::getCreateTime))
+                                )
+                ).collect(Collectors.toList());
 
-        return R.data(VOS);
+        return R.data(sortVOS);
     }
 
     @GetMapping("/contract/detail")

+ 16 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MiddleMeterApplyController.java

@@ -302,4 +302,20 @@ public class MiddleMeterApplyController extends BladeController {
         DeductStatisticsVO vo = middleMeterApplyService.deductStatistics(contractId);
         return R.data(vo);
     }
+
+    /**
+     * 自动批量计量
+     */
+    @GetMapping("/autoBatchMeter")
+    @ApiOperationSupport(order = 17)
+    @ApiOperation(value = "自动批量计量", notes = "传入项目id,合同id,计量期id")
+    @ApiImplicitParams(value = {
+            @ApiImplicitParam(name = "projectId", value = "项目id", required = true),
+            @ApiImplicitParam(name = "contractId", value = "合同id", required = true),
+            @ApiImplicitParam(name = "PeriodId", value = "计量期id", required = true),
+    })
+    public R<String> autoBatchMeter(Long projectId,Long contractId,Long PeriodId) {
+        String info = middleMeterApplyService.autoBatchMeter(projectId,contractId,PeriodId);
+        return R.success("计量完成:"+info);
+    }
 }

+ 1 - 1
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java

@@ -3019,7 +3019,7 @@ public class TaskController extends BladeController {
         Page<Map<String, Object>> resultMap = new Page<>();
         resultMap.setCurrent(dto.getCurrent());
         resultMap.setSize(dto.getSize());
-        resultMap.setTotal(jdbcTemplate.queryForObject("SELECT count(1) FROM u_fixed_flow WHERE is_deleted = 0 AND is_meter != 1 AND project_id = ? AND contract_id = ?", Long.class, dto.getProjectId(), dto.getContractId()));
+        resultMap.setTotal(jdbcTemplate.queryForObject("SELECT count(1) FROM u_fixed_flow WHERE is_deleted = 0 AND is_meter = 1 AND project_id = ? AND contract_id = ?", Long.class, dto.getProjectId(), dto.getContractId()));
         resultMap.setRecords(taskClient.getFixedFlowPage(dto));
         return R.data(resultMap);
     }

+ 4 - 3
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MeterTreeContractMapper.xml

@@ -55,12 +55,12 @@
         from s_meter_tree_contract mtc1 where project_id = #{projectId} and contract_id = #{contractId} and is_deleted = 0
     </select>
     <select id="getWBSTree" resultType="org.springblade.meter.vo.MeterFullTreeVO">
-        select p_key_id,id,node_name as nodeName,parent_id,
+        select p_key_id,id, if(full_name is null,node_name,full_name) as node_name,parent_id,
                if((select count(1) from m_wbs_tree_contract mtc2 where mtc2.project_id = #{projectId}
                    and mtc2.contract_id = #{contractId} and mtc2.type = 1  and is_deleted = 0 and mtc2.parent_id = mtc1.id) = 0,'false','true') as hasChild
         from m_wbs_tree_contract mtc1 where project_id = #{projectId} and contract_id = #{contractId} and mtc1.type = 1 and node_type != 111 and is_deleted = 0
         group by id
-        order by sort asc
+        order by  mtc1.sort,mtc1.full_name,mtc1.create_time
     </select>
     <select id="getContractName" resultType="java.lang.String">
         select contract_name from m_contract_info where id = #{contractId}
@@ -76,7 +76,8 @@
         group by meter_tree_id
     </select>
     <select id="getAllWbsNode" resultType="org.springblade.meter.vo.NodePartVO">
-        select p_key_id,id,parent_id,node_type,node_name
+        select p_key_id,id,parent_id,node_type,
+               if(full_name is null,node_name,full_name) as node_name
         from m_wbs_tree_contract where project_id = #{projectId} and contract_id = #{contractId} and type = 1 and is_deleted = 0
         group by id
     </select>

+ 11 - 4
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MiddleMeterApplyMapper.java

@@ -22,10 +22,7 @@ import org.springblade.business.entity.InformationQuery;
 import org.springblade.manager.entity.ContractInfo;
 import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.meter.dto.WbsNodeDTO;
-import org.springblade.meter.entity.ChangeTokenForm;
-import org.springblade.meter.entity.ChangeTokenMeter;
-import org.springblade.meter.entity.MeterTreeContract;
-import org.springblade.meter.entity.MiddleMeterApply;
+import org.springblade.meter.entity.*;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.springblade.meter.vo.*;
 
@@ -102,4 +99,14 @@ public interface MiddleMeterApplyMapper extends BaseMapper<MiddleMeterApply> {
     List<InformationQuery>  getQueryDataByIds(@Param("ids") List<Long> ids);
 
     List<MiddleMeterApply> getALLUnLinkDataApply(@Param("contractId") Long contractId);
+
+    List<MeterTreeContractVO2> getAllAutoMeterNode(@Param("contractId") Long contractId,@Param("periodId") Long periodId);
+
+    List<MeterLinkWbsInfoVO> getAllLinkWbsInfo(@Param("contractId") Long contractId,@Param("ids") HashSet<Long> hashSet);
+
+    List<WbsLinkQueryInfoVO> getQueryInfo(@Param("contractId") Long contractId,@Param("ids") HashSet<Long> hashSet);
+
+    List<InventoryFormMeterVO> getAllFormMeter(@Param("contractId")Long contractId,@Param("ids") List<Long> meterIds);
+
+
 }

+ 44 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/mapper/MiddleMeterApplyMapper.xml

@@ -328,6 +328,50 @@
         WHERE contract_id = #{contractId} and is_deleted = 0 and approve_status = 2
                 and is_link_data = 0
     </select>
+    <select id="getAllAutoMeterNode" resultType="org.springblade.meter.vo.MeterTreeContractVO2">
+        select id ,is_concrete_node,seven_ratio,twenty_eight_ratio,node_name,calculate_formula,
+               (select GROUP_CONCAT(lwt.wbs_tree_id) from s_meter_tree_link_wbs_tree lwt
+                    where lwt.contract_id = #{contractId} and smtc.id = lwt.meter_tree_id and lwt.is_deleted = 0) as linkWbs,
+               (select GROUP_CONCAT(ifm.contract_form_id) from s_inventory_form_meter ifm
+                    where ifm.contract_id = #{contractId} and smtc.id = ifm.contract_meter_id and ifm.is_deleted = 0) as linkForm,
+               (select GROUP_CONCAT(mma.id) from s_middle_meter_apply mma
+                    where mma.contract_id = #{contractId} and smtc.id = mma.contract_unit_id and mma.is_deleted = 0) as linkMiddle
+        from s_meter_tree_contract smtc where contract_id = #{contractId} and is_auto_meter = 1 and is_deleted = 0
+    </select>
+    <select id="getAllLinkWbsInfo" resultType="org.springblade.meter.vo.MeterLinkWbsInfoVO">
+        select p_key_id as id,
+               (select ifnull(MAX(uiq.status),0) from u_information_query uiq
+                    where uiq.contract_id = #{contractId} and uiq.classify = 1 and uiq.wbs_id = wtc.p_key_id
+                      and uiq.type = 1 and uiq.status != 3 and uiq.is_deleted = 0 ) as appStatus,
+               (select ifnull(MAX(mtf.type),0) from m_table_file mtf
+                    where mtf.contract_id = #{contractId} and mtf.tab_id = wtc.p_key_id and mtf.is_deleted = 0) as maxType,
+        from m_wbs_tree_contract wtc
+        where p_key_id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </select>
+    <select id="getQueryInfo" resultType="org.springblade.meter.vo.WbsLinkQueryInfoVO">
+        select id ,e_visa_pdf_url as eVisaPdf,wbs_id as wbsId,name
+        from u_information_query uiq
+        where uiq.contract_id = #{contractId} and uiq.classify = 1
+            and uiq.type = 1 and uiq.status = 2 and uiq.is_deleted = 0
+            and  uiq.wbs_id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </select>
+    <select id="getAllFormMeter" resultType="org.springblade.meter.vo.InventoryFormMeterVO">
+        select *,
+            IFNULL((select sum(current_meter_total) from s_inventory_form_apply ifa where ifa.contract_id = #{contractId} and is_deleted = 0
+                and ifa.contract_meter_id = ifm.contract_meter_id and ifa.contract_form_id = ifm.contract_form_id),0) as allMeterTotal
+        from s_inventory_form_meter ifm where contract_id = #{contractId} and is_deleted = 0
+        and contract_meter_id in
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </select>
+
 
 
 </mapper>

+ 5 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/IMiddleMeterApplyService.java

@@ -85,4 +85,9 @@ public interface IMiddleMeterApplyService extends BaseService<MiddleMeterApply>
      * 扣回统计
      */
     DeductStatisticsVO deductStatistics(Long contractId);
+
+    /**
+     * 自动批量计量
+     */
+    String autoBatchMeter(Long projectId,Long contractId, Long periodId);
 }

+ 269 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MiddleMeterApplyServiceImpl.java

@@ -78,6 +78,8 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
 
     private final IContractInventoryFormService inventoryFormService;
 
+    private final MeterContractInfoService meterContractInfoService;
+
 
 
     /**
@@ -485,6 +487,9 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
             //删除中间表当前中间计量申请数据
             inventoryFormApplyService.remove(new LambdaQueryWrapper<InventoryFormApply>()
                     .eq(InventoryFormApply::getMiddleMeterId,id));
+            //删除附件数据
+            attachmentFormService.remove(new LambdaQueryWrapper<AttachmentForm>()
+                    .eq(AttachmentForm::getMasterId,id));
         }
     }
 
@@ -985,6 +990,270 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
         return vo;
     }
 
+    @Override
+    @Transactional
+    public String autoBatchMeter(Long projectId,Long contractId, Long periodId) {
+        try {
+            /*校验,过滤允许自动计量的节点,并设置需要的相关属性值*/
+            //判断当前计量期是否是未上报
+            ContractMeterPeriod period = contractMeterPeriodService.getById(periodId);
+            if (period == null || period.getApproveStatus() != 0){
+                throw new ServiceException("当前计量期不是未上报状态");
+            }
+            //查询后台设置的支付比例,没有则提示
+            MeterContractInfo contractInfo = meterContractInfoService.getOne(new LambdaQueryWrapper<MeterContractInfo>()
+                        .eq(MeterContractInfo::getContractId,contractId));
+            if (contractInfo == null || contractInfo.getMiddlePayRatio() == null){
+                throw new ServiceException("后台未设置支付比例");
+            }
+            //查询出当前合同段所有允许自动计量的合同计量单元信息,并携带关联WBS节点逗号拼接,并携带关联清单的id逗号拼接,并携带当前计量期下当前合同计量单元的id,逗号拼接
+            List<MeterTreeContractVO2> voList = baseMapper.getAllAutoMeterNode(contractId,periodId);
+            //过滤,如果不存在关联WBS节点则排除,如果不存在挂载清单也排除,如果已经计量也排除
+            voList = voList.stream()
+                    .filter(l-> StringUtils.isNotBlank(l.getLinkWbs()) && StringUtils.isNotBlank(l.getLinkForm()) && StringUtils.isBlank(l.getLinkMiddle()))
+                    .collect(Collectors.toList());
+            if (voList.size() == 0){
+                throw new ServiceException("当前没有符合要求的合同计量单元-1");
+            }
+            //取出计量单元混凝土节点所有关联节点,查询->附带节点状态,附带每个节点最大附件type
+            List<MeterTreeContractVO2> vo2s = voList.stream().filter(l -> l.getIsConcreteNode() == 1).collect(Collectors.toList());
+            Map<Long, MeterLinkWbsInfoVO> wbsInfoVOMap = new HashMap<>();
+            if (vo2s.size() > 0) {
+                List<String> collect = voList.stream().map(l -> l.getLinkWbs()).collect(Collectors.toList());
+                String join = String.join(",", collect);
+                List<Long> wbsIds = Func.toLongList(join);
+                HashSet<Long> hashSet = new HashSet<>(wbsIds);
+                List<MeterLinkWbsInfoVO> vos = baseMapper.getAllLinkWbsInfo(contractId, hashSet);
+                //关联wbsId分组
+                wbsInfoVOMap = vos.stream().collect(Collectors.toMap(l -> l.getId(), l -> l));
+            }
+            //循环合同计量单元,过滤掉不符合要求的计量单元,
+            Iterator<MeterTreeContractVO2> iterator = voList.iterator();
+            //wbs拼接
+            StringBuilder str = new StringBuilder();
+            //计量单元id拼接
+            StringBuilder str2 = new StringBuilder();
+            //清单id拼接
+            StringBuilder str3 = new StringBuilder();
+            while (iterator.hasNext()){
+                MeterTreeContractVO2 vo2 = iterator.next();
+                //为混凝土节点,则去找寻附件
+                if (vo2.getIsConcreteNode() == 1) {
+                    List<Long> linkWbsIds = Func.toLongList(vo2.getLinkWbs());
+                    Boolean isApp = false;
+                    Integer strength = null;
+                    for (Long id : linkWbsIds) {
+                        MeterLinkWbsInfoVO vo = wbsInfoVOMap.get(id);
+                        if (vo.getAppStatus() != 2) {
+                            isApp = true;
+                            break;
+                        }
+                        if (vo.getMaxType() == 12) {
+                            strength = 28;
+                            break;
+                        }
+                        if (vo.getMaxType() == 11) {
+                            strength = 7;
+                        }
+                    }
+                    //审批不过通过,附件不存在7天或28天,直接过滤
+                    if (isApp || strength == null) {
+                        iterator.remove();
+                        continue;
+                    }
+                    //根据附件设置强度设置强度值
+                    if (strength == 7){
+                        vo2.setPayRatio(vo2.getSevenRatio());
+                    }else {
+                        vo2.setPayRatio(vo2.getTwentyEightRatio());
+                    }
+                }else {
+                    //不为混凝土节点,直接设置强度值为后管合同段默认
+                    vo2.setPayRatio(contractInfo.getMiddlePayRatio());
+                }
+                //末尾拼接所有WBS节点,所有计量节点
+                str.append(vo2.getLinkWbs()+",");
+                str2.append(vo2.getId());
+                str3.append(vo2.getLinkForm());
+
+            }
+            if (voList.size() == 0 || StringUtils.isBlank(str.toString()) || StringUtils.isBlank(str2.toString()) || StringUtils.isBlank(str3.toString())){
+                throw new ServiceException("当前没有符合要求的合同计量单元-2");
+            }
+            //根据拼接的所有WBS节点,去查询query表中的数据,然后转换为map,key为WBSId, 用于生成中间计量申请的附件。
+            List<Long> wbsIds = Func.toLongList((str.toString()));
+            HashSet<Long> hashSet = new HashSet<>(wbsIds);
+            List<WbsLinkQueryInfoVO> vos = baseMapper.getQueryInfo(contractId,hashSet);
+            Map<Long, WbsLinkQueryInfoVO> wbsMap = vos.stream().collect(Collectors.toMap(l -> l.getWbsId(), l -> l));
+            //根据拼接的所有计量节点,去查询清单与计量单元中间表数据(附带已经计量数),按计量节点id分组,用于生成中间计量申请的清单。
+            List<Long> meterIds = Func.toLongList((str2.toString()));
+            List<InventoryFormMeterVO> vos1 = baseMapper.getAllFormMeter(contractId,meterIds);
+            if (vos1.size() == 0){
+                throw new ServiceException("未找到关联的计量中间表信息");
+            }
+            Map<Long, List<InventoryFormMeterVO>> meterMap = vos1.stream().collect(Collectors.groupingBy(InventoryFormMeterVO::getContractMeterId));
+            //根据拼接的所有计量节点关联的表单id,查询表单数据,然后转换为map,key为表单id,用于生成中间计量申请的清单。
+            List<Long> formIds = Func.toLongList((str3.toString()));
+            HashSet<Long> hashSet2 = new HashSet<>(formIds);
+            List<ContractInventoryForm> vos2 = inventoryFormService.listByIds(hashSet2);
+            if (vos2.size() == 0){
+                throw new ServiceException("未找到关联的合同工程清单信息");
+            }
+            Map<Long, ContractInventoryForm> formMap = vos2.stream().collect(Collectors.toMap(l -> l.getId(), l -> l));
+
+            /*最终批量生成中间计量单,计量单与清单中间表,附件表*/
+            List<MiddleMeterApply> middleMeterApplyAdd = new ArrayList<>();
+            List<InventoryFormApply> inventoryFormApplyAdd = new ArrayList<>();
+            List<AttachmentForm> attachmentFormAdd = new ArrayList<>();
+            //获取当前计量期前缀
+            String prefix = this.getMeterNumberPrefix(contractId, periodId);
+            int count;
+            //查询出当前计量期所有未删除的计量单,如果不为空,则过滤出最大后缀
+            List<MiddleMeterApply> applyList = this.list(new LambdaQueryWrapper<MiddleMeterApply>()
+                    .eq(MiddleMeterApply::getContractId, contractId)
+                    .eq(MiddleMeterApply::getContractPeriodId, period));
+            //获取当前计量期所有已经计量的数量(),用于生成计量单编号
+            if (applyList.size() == 0){
+                count = 1;
+            }else {
+                Integer max = applyList.stream().map(l -> l.getMeterNumber()).map(l -> {
+                    String[] split = l.split("-");
+                    return Integer.parseInt(split[2]);
+                }).max(Integer::compareTo).orElse(0);
+                count = ++max;
+            }
+            //循环合同计量单元,获取中间表集合
+            for (MeterTreeContractVO2 vo2 : voList) {
+                //new中间计量单,并创建计量金额初始值,在下面循环中统计
+                MiddleMeterApply apply = new MiddleMeterApply();
+                Long middleId = SnowFlakeUtil.getId();
+                apply.setId(middleId);
+                BigDecimal total = BigDecimal.ZERO;
+                //循环中间表,取出计量单元中的比例,new中间表对象
+                List<InventoryFormMeterVO> formMeters = meterMap.get(vo2.getId());
+                if (formMeters == null || formMeters.size() == 0){
+                    throw new ServiceException("节点:("+vo2.getNodeName()+")未找到清单中间表信息");
+                }
+                //判断是否有需要计量的清单,如果没有则连中间计量单都不保存
+                int formTotal = 0;
+                for (InventoryFormMeterVO vo : formMeters) {
+                     /*
+                        变更后施工图数量 * 比例 = 最大可以计量的数量
+                        if 当前已经计量的数量 >= 最大可以计量的数量,则跳过
+                        else 最大施工图数量 - 已经计量数 = 当前期计量数
+                     */
+                    BigDecimal changeBuildPictureTotal = vo.getChangeBuildPictureTotal();
+                    if (changeBuildPictureTotal == null || changeBuildPictureTotal.compareTo(BigDecimal.ZERO) == 0){
+                        continue;
+                    }
+                    BigDecimal payRatio = vo2.getPayRatio();
+                    BigDecimal maxMeterTotal = changeBuildPictureTotal.multiply(payRatio).divide(new BigDecimal(100));
+                    if (vo.getAllMeterTotal().compareTo(maxMeterTotal) >= 0){
+                        continue;
+                    }
+                    //根据清单id获取清单信息
+                    ContractInventoryForm form = formMap.get(vo.getContractFormId());
+                    //生成中间计量与清单中间表数据
+                    InventoryFormApply inventoryFormApply = new InventoryFormApply();
+                    inventoryFormApply.setProjectId(projectId);
+                    inventoryFormApply.setContractId(contractId);
+                    inventoryFormApply.setMiddleMeterId(middleId);
+                    inventoryFormApply.setContractFormId(vo.getContractFormId());
+                    inventoryFormApply.setContractMeterId(vo.getContractMeterId());
+                    inventoryFormApply.setContractPeriodId(periodId);
+                    //表单基础信息
+                    inventoryFormApply.setFormNumber(form.getFormNumber());
+                    inventoryFormApply.setFormName(form.getFormName());
+                    inventoryFormApply.setCurrentPrice(form.getCurrentPrice());
+                    inventoryFormApply.setBuildPictureTotal(vo.getBuildPictureTotal());
+                    inventoryFormApply.setChangeBuildPictureTotal(vo.getChangeBuildPictureTotal());
+                    //计量信息
+                    inventoryFormApply.setCurrentMeterTotal(maxMeterTotal.subtract(vo.getAllMeterTotal()));
+                    inventoryFormApply.setCurrentMeterMoney(inventoryFormApply.getCurrentMeterTotal().multiply(inventoryFormApply.getCurrentPrice()));
+                    inventoryFormApply.setBusinessDate(period.getEndDate());
+                    total = total.add(inventoryFormApply.getCurrentMeterMoney());
+                    //加入计量单与清单中间表集合
+                    inventoryFormApplyAdd.add(inventoryFormApply);
+                    formTotal++;
+                }
+                if (formTotal == 0){
+                    continue;
+                }
+                //循环关联的wbsId,获取query数据
+                List<Long> longs = Func.toLongList(vo2.getLinkWbs());
+                for (Long aLong : longs) {
+                    //new 中间计量申请的附件,通过query数据填写信息
+                    WbsLinkQueryInfoVO vo = wbsMap.get(aLong);
+                    if (vo == null || StringUtils.isBlank(vo.getEVisaPdf())){
+                        throw new ServiceException("合同计量单元("+vo2.getNodeName()+")所关联的WBS节点id:"+aLong+"未找到电签PDF");
+                    }
+                    AttachmentForm form = new AttachmentForm();
+                    form.setProjectId(projectId);
+                    form.setContractId(contractId);
+                    form.setMasterId(middleId);
+                    form.setFileName(vo.getName());
+                    form.setFileUrl(vo.getEVisaPdf());
+                    form.setFilePdfUrl(vo.getEVisaPdf());
+                    form.setFileType(1);
+                    form.setSelectId(vo.getId());
+                    //添加到附件表
+                    attachmentFormAdd.add(form);
+                }
+                //设置中间计量申请属性
+                apply.setProjectId(projectId);
+                apply.setContractId(contractId);
+                apply.setContractUnitId(vo2.getId());
+                apply.setContractPeriodId(periodId);
+                apply.setPeriodNumber(period.getPeriodNumber());
+                //生成计量单编号
+                apply.setMeterNumber(prefix+count);
+                apply.setBusinessDate(period.getEndDate());
+                apply.setEngineerDivide(this.getNodeDivide(vo2.getId()));
+                apply.setMeterMoney(total);
+                apply.setCalculateFormula(vo2.getCalculateFormula());
+                apply.setIsLinkData(1);
+                //添加到计量单集合
+                middleMeterApplyAdd.add(apply);
+                count++;
+            }
+            /*执行保存*/
+            if (middleMeterApplyAdd.size() > 0){
+                this.saveBatch(middleMeterApplyAdd);
+            }
+            if (inventoryFormApplyAdd.size() > 0){
+                inventoryFormApplyService.saveBatch(inventoryFormApplyAdd);
+            }
+            if (attachmentFormAdd.size() > 0){
+                attachmentFormService.saveBatch(attachmentFormAdd);
+            }
+            return "共生成"+middleMeterApplyAdd.size()+"条计量单";
+        }catch (Exception e){
+            throw new ServiceException("自动生成失败:"+e.getMessage());
+        }
+        
+    }
+
+    /**
+     *  获取当前计量期计量单前缀
+     */
+    private String getMeterNumberPrefix(Long contractId,Long periodId){
+        StringBuilder str = new StringBuilder();
+        //获取合同信息
+        ContractInfo info = baseMapper.getContractInfo(contractId);
+        String contractNumber = info.getContractNumber();
+        if (StringUtils.isBlank(contractNumber)){
+            throw new ServiceException("未获取到当前合同段编号信息");
+        }
+        str.append(contractNumber+"-");
+        //获取计量期信息
+        ContractMeterPeriod contractMeterPeriod = contractMeterPeriodService.getById(periodId);
+        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())){
+            throw new ServiceException("未获取到计量期期号信息");
+        }
+        str.append(contractMeterPeriod.getPeriodNumber()+"-");
+        return str.toString();
+    }
+
     //递归方法
     private void gatherSortNode(List<NodeSortVO> list,List<Long> ids){
         for (NodeSortVO vo : list) {