Commit 33f4e34caf479f0971bde8dba499d9342068f79d

Authored by 杨鸣坤
1 parent 4fe232dc

楚江ERP:经销合同打印

1 package com.lframework.xingyun.sc.controller.contract; 1 package com.lframework.xingyun.sc.controller.contract;
2 2
  3 +import cn.hutool.core.io.resource.ClassPathResource;
3 import com.baomidou.mybatisplus.core.conditions.Wrapper; 4 import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 import com.baomidou.mybatisplus.core.toolkit.Wrappers; 5 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
5 import com.lframework.starter.common.exceptions.impl.DefaultClientException; 6 import com.lframework.starter.common.exceptions.impl.DefaultClientException;
@@ -21,8 +22,10 @@ import com.lframework.starter.web.inner.service.system.SysDataDicItemService; @@ -21,8 +22,10 @@ import com.lframework.starter.web.inner.service.system.SysDataDicItemService;
21 import com.lframework.starter.web.inner.service.system.SysDeptService; 22 import com.lframework.starter.web.inner.service.system.SysDeptService;
22 import com.lframework.starter.web.inner.service.system.SysUserService; 23 import com.lframework.starter.web.inner.service.system.SysUserService;
23 import com.lframework.xingyun.basedata.entity.Customer; 24 import com.lframework.xingyun.basedata.entity.Customer;
  25 +import com.lframework.xingyun.basedata.entity.ProductVariety;
24 import com.lframework.xingyun.basedata.entity.Workshop; 26 import com.lframework.xingyun.basedata.entity.Workshop;
25 import com.lframework.xingyun.basedata.service.customer.CustomerService; 27 import com.lframework.xingyun.basedata.service.customer.CustomerService;
  28 +import com.lframework.xingyun.basedata.service.product.ProductVarietyService;
26 import com.lframework.xingyun.basedata.service.workshop.WorkshopService; 29 import com.lframework.xingyun.basedata.service.workshop.WorkshopService;
27 import com.lframework.xingyun.basedata.vo.customer.QueryCustomerVo; 30 import com.lframework.xingyun.basedata.vo.customer.QueryCustomerVo;
28 import com.lframework.xingyun.sc.bo.contract.GetContractDistributorLineBo; 31 import com.lframework.xingyun.sc.bo.contract.GetContractDistributorLineBo;
@@ -31,26 +34,38 @@ import com.lframework.xingyun.sc.bo.contract.QueryContractDistributorStandardBo; @@ -31,26 +34,38 @@ import com.lframework.xingyun.sc.bo.contract.QueryContractDistributorStandardBo;
31 import com.lframework.xingyun.sc.components.code.GenerateCodeTypePool; 34 import com.lframework.xingyun.sc.components.code.GenerateCodeTypePool;
32 import com.lframework.xingyun.sc.entity.ContractDistributorLine; 35 import com.lframework.xingyun.sc.entity.ContractDistributorLine;
33 import com.lframework.xingyun.sc.entity.ContractDistributorStandard; 36 import com.lframework.xingyun.sc.entity.ContractDistributorStandard;
  37 +import com.lframework.xingyun.sc.entity.ContractFramework;
34 import com.lframework.xingyun.sc.service.contract.ContractDistributorLineService; 38 import com.lframework.xingyun.sc.service.contract.ContractDistributorLineService;
35 import com.lframework.xingyun.sc.service.contract.ContractDistributorStandardService; 39 import com.lframework.xingyun.sc.service.contract.ContractDistributorStandardService;
  40 +import com.lframework.xingyun.sc.service.contract.ContractFrameworkService;
36 import com.lframework.xingyun.sc.vo.contract.createVo.CreateContractDistributorStandardVo; 41 import com.lframework.xingyun.sc.vo.contract.createVo.CreateContractDistributorStandardVo;
37 import com.lframework.xingyun.sc.vo.contract.queryVo.QueryContractDistributorStandardVo; 42 import com.lframework.xingyun.sc.vo.contract.queryVo.QueryContractDistributorStandardVo;
38 import com.lframework.xingyun.sc.vo.contract.updateVo.UpdateContractDistributorStandardVo; 43 import com.lframework.xingyun.sc.vo.contract.updateVo.UpdateContractDistributorStandardVo;
39 import io.swagger.annotations.Api; 44 import io.swagger.annotations.Api;
40 import io.swagger.annotations.ApiImplicitParam; 45 import io.swagger.annotations.ApiImplicitParam;
41 import io.swagger.annotations.ApiOperation; 46 import io.swagger.annotations.ApiOperation;
  47 +import lombok.extern.slf4j.Slf4j;
42 import org.apache.commons.collections4.CollectionUtils; 48 import org.apache.commons.collections4.CollectionUtils;
  49 +import org.apache.commons.lang3.BooleanUtils;
43 import org.apache.commons.lang3.StringUtils; 50 import org.apache.commons.lang3.StringUtils;
  51 +import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  52 +import org.apache.poi.ss.usermodel.*;
  53 +import org.apache.poi.util.IOUtils;
44 import org.springframework.beans.factory.annotation.Autowired; 54 import org.springframework.beans.factory.annotation.Autowired;
45 import org.springframework.validation.annotation.Validated; 55 import org.springframework.validation.annotation.Validated;
46 import org.springframework.web.bind.annotation.*; 56 import org.springframework.web.bind.annotation.*;
47 57
  58 +import javax.servlet.http.HttpServletResponse;
48 import javax.validation.Valid; 59 import javax.validation.Valid;
49 import javax.validation.constraints.NotBlank; 60 import javax.validation.constraints.NotBlank;
50 -import java.util.ArrayList;  
51 -import java.util.Arrays;  
52 -import java.util.List;  
53 -import java.util.Map; 61 +import java.io.FileNotFoundException;
  62 +import java.io.IOException;
  63 +import java.io.InputStream;
  64 +import java.math.BigDecimal;
  65 +import java.net.URLEncoder;
  66 +import java.time.LocalDate;
  67 +import java.time.format.DateTimeFormatter;
  68 +import java.util.*;
54 import java.util.function.Function; 69 import java.util.function.Function;
55 import java.util.stream.Collectors; 70 import java.util.stream.Collectors;
56 71
@@ -61,6 +76,7 @@ import java.util.stream.Collectors; @@ -61,6 +76,7 @@ import java.util.stream.Collectors;
61 @Validated 76 @Validated
62 @RestController 77 @RestController
63 @RequestMapping("/contract/contractDistributorStandard") 78 @RequestMapping("/contract/contractDistributorStandard")
  79 +@Slf4j
64 public class ContractDistributorStandardController extends DefaultBaseController { 80 public class ContractDistributorStandardController extends DefaultBaseController {
65 81
66 @Autowired 82 @Autowired
@@ -81,6 +97,10 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -81,6 +97,10 @@ public class ContractDistributorStandardController extends DefaultBaseController
81 private DicCityService dicCityService; 97 private DicCityService dicCityService;
82 @Autowired 98 @Autowired
83 private WorkshopService workshopService; 99 private WorkshopService workshopService;
  100 + @Autowired
  101 + private ContractFrameworkService contractFrameworkService;
  102 + @Autowired
  103 + private ProductVarietyService productVarietyService;
84 104
85 105
86 public static final String SUPPLIER_DIC_CODE = "SUPPLIER"; // 所属单位/供方 106 public static final String SUPPLIER_DIC_CODE = "SUPPLIER"; // 所属单位/供方
@@ -407,4 +427,203 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -407,4 +427,203 @@ public class ContractDistributorStandardController extends DefaultBaseController
407 427
408 return InvokeResultBuilder.success(new GetContractDistributorStandardBo(contractDistributorStandard)); 428 return InvokeResultBuilder.success(new GetContractDistributorStandardBo(contractDistributorStandard));
409 } 429 }
  430 +
  431 + /**
  432 + * 标准合同模版打印
  433 + */
  434 + @ApiOperation("标准合同模版打印")
  435 + @GetMapping("/printStandardContract")
  436 + public void printStandardContract(@NotBlank(message = "合同不可为空") String id, HttpServletResponse response) throws IOException {
  437 + InvokeResult<GetContractDistributorStandardBo> result = get(id);
  438 + GetContractDistributorStandardBo data = result.getData();
  439 +
  440 + // 设置响应头
  441 + setupResponse(response, data.getCode() + "_" + data.getBuyerName() + "-合同打印.xls");
  442 +
  443 + Wrapper<ContractFramework> contractFrameworkWrapper = Wrappers.lambdaQuery(ContractFramework.class)
  444 + .eq(ContractFramework::getCustomerId, data.getBuyer())
  445 + .ge(ContractFramework::getValidityTime, LocalDate.now())
  446 + .eq(ContractFramework::getHasFrameworkAgreement, true);
  447 + List<ContractFramework> contractFrameworkList = contractFrameworkService.list(contractFrameworkWrapper);
  448 + List<String> productNameList = new ArrayList<>();
  449 + if (CollectionUtils.isNotEmpty(contractFrameworkList)) {
  450 + List<String> materialTypeIdList = contractFrameworkList.stream()
  451 + .filter(bo -> StringUtils.isNotBlank(bo.getMaterialTypeId()))
  452 + .flatMap(bo -> Arrays.stream(bo.getMaterialTypeId().split(",")))
  453 + .map(String::trim)
  454 + .filter(StringUtils::isNotBlank)
  455 + .distinct()
  456 + .collect(Collectors.toList());
  457 + List<ProductVariety> productVarietyList = productVarietyService.listByIds(materialTypeIdList);
  458 + CollectionUtils.emptyIfNull(productVarietyList).forEach(productVariety -> {
  459 + if (productVariety == null || StringUtils.isBlank(productVariety.getName())) {
  460 + return;
  461 + }
  462 +
  463 + productNameList.add(productVariety.getName().substring(0, 2));
  464 + });
  465 + }
  466 +
  467 + try {
  468 + // 加载模板文件
  469 + ClassPathResource templateResource = new ClassPathResource("templates/standardContractTemplate.xls");
  470 + try (InputStream inputStream = templateResource.getStream();
  471 + Workbook workbook = new HSSFWorkbook(inputStream)) {
  472 + try {
  473 + Sheet sheet = workbook.getSheetAt(0);
  474 + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  475 + int startRow = 6; // 产品开始行
  476 + String contractTitle = "销售订单(经销)";
  477 + if (CollectionUtils.isNotEmpty(data.getContractDistributorLineList())) {
  478 + for (GetContractDistributorLineBo contractDistributorLineBo : data.getContractDistributorLineList()) {
  479 + if (StringUtils.isNotBlank(contractDistributorLineBo.getProductName())
  480 + && !productNameList.contains(contractDistributorLineBo.getProductName().substring(0, 2))) {
  481 + contractTitle = "销售合同(经销)";
  482 + }
  483 +
  484 + setCellValue(sheet, startRow, 1, contractDistributorLineBo.getProductName()); // B列
  485 + setCellValue(sheet, startRow, 4, contractDistributorLineBo.getBrand()); // D列
  486 +// setCellValue(sheet, startRow, 5, contractDistributorLineBo.getSpecification()); // E列
  487 + setCellValue(sheet, startRow, 6, contractDistributorLineBo.getStatus()); // F列
  488 + setCellValue(sheet, startRow, 7, contractDistributorLineBo.getQuantity()); // G列
  489 + setCellValue(sheet, startRow, 9, contractDistributorLineBo.getUnitPrice()); // I列
  490 + setCellValue(sheet, startRow, 10, contractDistributorLineBo.getAmountExcludingTax()); // K列
  491 + setCellValue(sheet, startRow, 11, contractDistributorLineBo.getTotalAmount()); // L列
  492 + setCellValue(sheet, startRow, 12, contractDistributorLineBo.getDeliveryDate() != null ?
  493 + contractDistributorLineBo.getDeliveryDate().format(dateFormatter) : ""); // L列
  494 + startRow++;
  495 + }
  496 + }
  497 +
  498 + Map<String, Object> dataMap = new HashMap<>();
  499 + dataMap.put("title", contractTitle);
  500 + dataMap.put("code", data.getCode());
  501 + dataMap.put("orderDate", data.getOrderDate().format(dateFormatter));
  502 + dataMap.put("supplierName", data.getSupplierName());
  503 + dataMap.put("buyerName", data.getBuyerName());
  504 + dataMap.put("unitName", data.getUnitName());
  505 +
  506 + dataMap.put("totalQuantity", data.getTotalQuantity());
  507 + dataMap.put("totalAmountExcludingTax", data.getTotalAmountExcludingTax());
  508 + dataMap.put("totalAmountIncludingTax", data.getTotalAmountIncludingTax());
  509 + dataMap.put("totalAmountCapital", data.getTotalAmountCapital());
  510 +
  511 + dataMap.put("depositInfo", data.getDepositInfo());
  512 + dataMap.put("paymentTerms", data.getPaymentTerms());
  513 + dataMap.put("packagingRequirements", data.getPackagingRequirements());
  514 + dataMap.put("transportMode", data.getTransportMode());
  515 + if (BooleanUtils.isTrue(data.getIncludesPackagingFee()) && BooleanUtils.isTrue(data.getIncludesTransportFee())) {
  516 + dataMap.put("includesTransportOrPackaging", "单价中已包含包装费用与运费");
  517 + } else if (BooleanUtils.isTrue(data.getIncludesPackagingFee()) && BooleanUtils.isNotTrue(data.getIncludesTransportFee())) {
  518 + dataMap.put("includesTransportOrPackaging", "单价中已包含包装费用,不包含运费");
  519 + } else if (BooleanUtils.isNotTrue(data.getIncludesPackagingFee()) && BooleanUtils.isTrue(data.getIncludesTransportFee())) {
  520 + dataMap.put("includesTransportOrPackaging", "单价中不包含包装费用,包含运费");
  521 + } else if (BooleanUtils.isNotTrue(data.getIncludesPackagingFee()) && BooleanUtils.isNotTrue(data.getIncludesTransportFee())) {
  522 + dataMap.put("includesTransportOrPackaging", "单价中不包含包装费用与运费");
  523 + }
  524 +
  525 + dataMap.put("remarks", data.getRemarks());
  526 + processTemplate(workbook, dataMap);
  527 +
  528 + // 写入响应流
  529 + workbook.write(response.getOutputStream());
  530 + response.getOutputStream().flush();
  531 + } finally {
  532 + IOUtils.closeQuietly(workbook);
  533 + }
  534 +
  535 + } catch (FileNotFoundException e) {
  536 + throw new RuntimeException("模板文件不存在: templates/standardContractTemplate.xls", e);
  537 + } catch (IOException e) {
  538 + throw new RuntimeException("无法读取模板文件: templates/standardContractTemplate.xls", e);
  539 + }
  540 + } catch (Exception e) {
  541 + log.error("标准合同模版打印: {}", e.getMessage(), e);
  542 + throw e;
  543 + }
  544 + }
  545 +
  546 + private void processTemplate(Workbook workbook, Map<String, Object> dataMap) {
  547 + Sheet sheet = workbook.getSheetAt(0);
  548 +
  549 + for (Row row : sheet) {
  550 + for (Cell cell : row) {
  551 + if (cell.getCellTypeEnum() == CellType.STRING) {
  552 + String cellValue = cell.getStringCellValue();
  553 + String newValue = replacePlaceholders(cellValue, dataMap);
  554 + if (!cellValue.equals(newValue)) {
  555 + cell.setCellValue(newValue);
  556 + }
  557 + }
  558 + }
  559 + }
  560 + }
  561 +
  562 + private String replacePlaceholders(String text, Map<String, Object> dataMap) {
  563 + if (text == null || text.isEmpty()) {
  564 + return text;
  565 + }
  566 +
  567 + String result = text;
  568 + for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
  569 + String placeholder = "${" + entry.getKey() + "}";
  570 + String value = entry.getValue() != null ? entry.getValue().toString() : "";
  571 + // 将数据库中的 \n 转换为 Excel 识别的换行符
  572 + value = value.replace("\\n", "\n");
  573 +
  574 + result = result.replace(placeholder, value);
  575 + }
  576 +
  577 + for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
  578 + String placeholder = "#{" + entry.getKey() + "}";
  579 + String value = entry.getValue() != null ? entry.getValue().toString() : "";
  580 + // 将数据库中的 \n 转换为 Excel 识别的换行符
  581 + value = value.replace("\\n", "\n");
  582 +
  583 + result = result.replace(placeholder, value);
  584 + }
  585 +
  586 + return result;
  587 + }
  588 +
  589 + /**
  590 + * 设置HTTP响应头
  591 + */
  592 + private void setupResponse(HttpServletResponse response, String fileName) throws IOException {
  593 + String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
  594 +
  595 + response.setContentType("application/vnd.ms-excel");
  596 + response.setCharacterEncoding("UTF-8");
  597 + response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
  598 + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
  599 + }
  600 +
  601 + /**
  602 + * 设置单元格值
  603 + */
  604 + private static void setCellValue(Sheet sheet, int rowNum, int colNum, Object value) {
  605 + Row row = sheet.getRow(rowNum);
  606 + if (row == null) {
  607 + row = sheet.createRow(rowNum);
  608 + }
  609 +
  610 + Cell cell = row.getCell(colNum);
  611 + if (cell == null) {
  612 + cell = row.createCell(colNum);
  613 + }
  614 +
  615 + if (value == null) {
  616 + cell.setCellValue("");
  617 + } else if (value instanceof String) {
  618 + cell.setCellValue((String) value);
  619 + } else if (value instanceof Integer) {
  620 + cell.setCellValue((Integer) value);
  621 + } else if (value instanceof Double) {
  622 + cell.setCellValue((Double) value);
  623 + } else if (value instanceof BigDecimal) {
  624 + cell.setCellValue(((BigDecimal) value).doubleValue());
  625 + } else if (value instanceof LocalDate) {
  626 + cell.setCellValue(((LocalDate) value).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
  627 + }
  628 + }
410 } 629 }
@@ -5,27 +5,19 @@ import com.lframework.starter.common.utils.DateUtil; @@ -5,27 +5,19 @@ import com.lframework.starter.common.utils.DateUtil;
5 import com.lframework.starter.web.core.bo.BaseBo; 5 import com.lframework.starter.web.core.bo.BaseBo;
6 import com.lframework.starter.web.core.components.excel.ExcelModel; 6 import com.lframework.starter.web.core.components.excel.ExcelModel;
7 import com.lframework.starter.web.core.utils.ApplicationUtil; 7 import com.lframework.starter.web.core.utils.ApplicationUtil;
8 -import com.lframework.starter.web.inner.dto.dic.city.DicCityDto;  
9 import com.lframework.starter.web.inner.entity.SysDataDicItem; 8 import com.lframework.starter.web.inner.entity.SysDataDicItem;
10 -import com.lframework.starter.web.inner.service.DicCityService;  
11 import com.lframework.starter.web.inner.service.system.SysDataDicItemService; 9 import com.lframework.starter.web.inner.service.system.SysDataDicItemService;
12 -import com.lframework.xingyun.basedata.entity.*;  
13 -import com.lframework.xingyun.basedata.enums.AddressEntityType; 10 +import com.lframework.xingyun.basedata.entity.Customer;
  11 +import com.lframework.xingyun.basedata.entity.ProductVariety;
14 import com.lframework.xingyun.basedata.service.customer.CustomerService; 12 import com.lframework.xingyun.basedata.service.customer.CustomerService;
15 -import com.lframework.xingyun.basedata.service.member.MemberService;  
16 import com.lframework.xingyun.basedata.service.product.ProductVarietyService; 13 import com.lframework.xingyun.basedata.service.product.ProductVarietyService;
17 -import com.lframework.xingyun.basedata.service.shop.ShopService;  
18 -import com.lframework.xingyun.basedata.service.storecenter.StoreCenterService;  
19 -import com.lframework.xingyun.basedata.service.supplier.SupplierService;  
20 import com.lframework.xingyun.sc.controller.contract.ContractFrameworkController; 14 import com.lframework.xingyun.sc.controller.contract.ContractFrameworkController;
21 import com.lframework.xingyun.sc.entity.ContractFramework; 15 import com.lframework.xingyun.sc.entity.ContractFramework;
22 -import io.swagger.annotations.ApiModelProperty;  
23 import lombok.Data; 16 import lombok.Data;
24 import org.apache.commons.collections4.CollectionUtils; 17 import org.apache.commons.collections4.CollectionUtils;
25 import org.apache.commons.lang3.BooleanUtils; 18 import org.apache.commons.lang3.BooleanUtils;
26 import org.apache.commons.lang3.StringUtils; 19 import org.apache.commons.lang3.StringUtils;
27 20
28 -import java.time.format.DateTimeFormatter;  
29 import java.util.*; 21 import java.util.*;
30 import java.util.stream.Collectors; 22 import java.util.stream.Collectors;
31 23
@@ -59,7 +51,7 @@ public class ContractFrameworkExportModel extends BaseBo<ContractFramework> impl @@ -59,7 +51,7 @@ public class ContractFrameworkExportModel extends BaseBo<ContractFramework> impl
59 /** 51 /**
60 * 品种名称 52 * 品种名称
61 */ 53 */
62 - @ApiModelProperty("品种") 54 + @ExcelProperty("品种")
63 private String materialTypeName; 55 private String materialTypeName;
64 56
65 /** 57 /**