From 1049c1f0bcc7e6ba34ed005ba57ea5b4b77efbc5 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期三, 18 三月 2026 15:41:55 +0800
Subject: [PATCH] fix(sales): 补全乙方信息和公司名称

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java |  274 +++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 176 insertions(+), 98 deletions(-)

diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index 03635b4..94fbcd4 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -1,5 +1,11 @@
 package com.ruoyi.sales.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -8,38 +14,37 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
 import com.ruoyi.account.service.AccountIncomeService;
-import com.ruoyi.aftersalesservice.pojo.AfterSalesService;
 import com.ruoyi.basic.mapper.CustomerMapper;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.Customer;
 import com.ruoyi.common.enums.FileNameType;
+import com.ruoyi.common.enums.SaleEnum;
 import com.ruoyi.common.exception.base.BaseException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.*;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.other.mapper.TempFileMapper;
 import com.ruoyi.other.pojo.TempFile;
 import com.ruoyi.production.mapper.*;
-import com.ruoyi.production.pojo.*;
 import com.ruoyi.production.service.ProductionProductMainService;
-import com.ruoyi.production.service.impl.ProductionProductMainServiceImpl;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysDeptMapper;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.sales.dto.*;
 import com.ruoyi.sales.mapper.*;
 import com.ruoyi.sales.pojo.*;
-import com.ruoyi.sales.service.ISalesLedgerProductService;
 import com.ruoyi.sales.service.ISalesLedgerService;
+import com.ruoyi.sales.vo.ExportProcessContractVo;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FilenameUtils;
 import org.springframework.beans.BeanUtils;
@@ -49,8 +54,12 @@
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotNull;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Field;
@@ -79,69 +88,41 @@
 @RequiredArgsConstructor
 @Slf4j
 public class SalesLedgerServiceImpl extends ServiceImpl<SalesLedgerMapper, SalesLedger> implements ISalesLedgerService {
-    private final AccountIncomeService accountIncomeService;
-
-    private final SalesLedgerMapper salesLedgerMapper;
-
-    private final CustomerMapper customerMapper;
-
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
-
-    private final CommonFileMapper commonFileMapper;
-
-    private final TempFileMapper tempFileMapper;
-
-    private final ReceiptPaymentMapper receiptPaymentMapper;
-
-    private final ShippingInfoServiceImpl shippingInfoServiceImpl;
-
-    private final CommonFileServiceImpl commonFileService;
-
-    private final ShippingInfoMapper shippingInfoMapper;
-
-    private final InvoiceLedgerMapper invoiceLedgerMapper;
-
-    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
-
-    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
-
-    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
-
-    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-
-    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
-
-    private final ProductOrderMapper productOrderMapper;
-
-    private final ProcessRouteMapper processRouteMapper;
-    private final ProductProcessRouteMapper productProcessRouteMapper;
-
-    private final ProcessRouteItemMapper processRouteItemMapper;
-
-    private final ProductProcessRouteItemMapper productProcessRouteItemMapper;
-
-    private final ProductWorkOrderMapper productWorkOrderMapper;
-
-    private final ProductionProductMainMapper productionProductMainMapper;
-
-    private final ProductionProductOutputMapper productionProductOutputMapper;
-
-    private final ProductionProductInputMapper productionProductInputMapper;
-
-    private final QualityInspectMapper qualityInspectMapper;
-
-    @Autowired
-    private SysDeptMapper sysDeptMapper;
-
-    @Value("${file.upload-dir}")
-    private String uploadDir;
-
     private static final String LOCK_PREFIX = "contract_no_lock:";
     private static final long LOCK_WAIT_TIMEOUT = 10; // 閿佺瓑寰呰秴鏃舵椂闂达紙绉掞級
     private static final long LOCK_EXPIRE_TIME = 30;  // 閿佽嚜鍔ㄨ繃鏈熸椂闂达紙绉掞級
-
+    private final AccountIncomeService accountIncomeService;
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final CustomerMapper customerMapper;
+    private final SalesLedgerProductMapper salesLedgerProductMapper;
+    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
+    private final CommonFileMapper commonFileMapper;
+    private final TempFileMapper tempFileMapper;
+    private final ReceiptPaymentMapper receiptPaymentMapper;
+    private final ShippingInfoServiceImpl shippingInfoServiceImpl;
+    private final CommonFileServiceImpl commonFileService;
+    private final ShippingInfoMapper shippingInfoMapper;
+    private final InvoiceLedgerMapper invoiceLedgerMapper;
+    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
+    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
+    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
+    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
+    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
+    private final ProductOrderMapper productOrderMapper;
+    private final ProcessRouteMapper processRouteMapper;
+    private final ProductProcessRouteMapper productProcessRouteMapper;
+    private final ProcessRouteItemMapper processRouteItemMapper;
+    private final ProductProcessRouteItemMapper productProcessRouteItemMapper;
+    private final ProductWorkOrderMapper productWorkOrderMapper;
+    private final ProductionProductMainMapper productionProductMainMapper;
+    private final ProductionProductOutputMapper productionProductOutputMapper;
+    private final ProductionProductInputMapper productionProductInputMapper;
+    private final QualityInspectMapper qualityInspectMapper;
     private final RedisTemplate<String, String> redisTemplate;
+    @Autowired
+    private SysDeptMapper sysDeptMapper;
+    @Value("${file.upload-dir}")
+    private String uploadDir;
     @Autowired
     private ProductModelMapper productModelMapper;
 
@@ -152,10 +133,19 @@
     @Autowired
     private ProductionProductMainService productionProductMainService;
     ;
+    @Autowired
+    private SysUserMapper sysUserMapper;
 
     @Override
     public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
         return salesLedgerMapper.selectSalesLedgerList(salesLedgerDto);
+    }
+
+    public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type) {
+        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
+        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, relateId);
+        productWrapper.eq(SalesLedgerProduct::getType, type.getCode());
+        return salesLedgerProductMapper.selectList(productWrapper);
     }
 
     @Override
@@ -329,9 +319,6 @@
         return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
     }
 
-    @Autowired
-    private SysUserMapper sysUserMapper;
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     public AjaxResult importData(MultipartFile file) {
@@ -487,35 +474,96 @@
         return salesLedgerDtoIPage;
     }
 
+    @Override
+    public void exportProcessContract(Long id) {
+        //鍔犲伐鎵挎徑鍚堝悓
+        ExportProcessContractVo exportProcessContract = new ExportProcessContractVo();
+        exportProcessContract.setId(id);
+        SalesLedger salesLedger = salesLedgerMapper.selectById(id);
+        // 鏌ヨ瀹㈡埛鍏徃淇℃伅
+        Customer customer = customerMapper.selectById(salesLedger.getCustomerId());
+        exportProcessContract.setCreateTime(LocalDateTimeUtil.format(Optional.ofNullable(salesLedger.getExecutionDate()).orElse(LocalDate.now()), "yyyy骞碝M鏈坉d鏃�"));
+        exportProcessContract.setRemark(Optional.ofNullable(salesLedger.getRemarks()).orElse("鏃�")); // 澶囨敞
+        exportProcessContract.setPlaceOfSinging(Optional.ofNullable(salesLedger.getPlaceOfSinging()).orElse(""));
 
-    // 鍐呴儴绫荤敤浜庡瓨鍌ㄨ仛鍚堢粨鏋�
-    private static class GroupedCustomer {
-        private final Long customerId;
-        private final String customerName;
-        private BigDecimal totalAmount = BigDecimal.ZERO;
+        // 濉啓鐢叉柟淇℃伅
+        ExportProcessContractVo.Customer partyA = ExportProcessContractVo.Customer.getCustomer(customer);
+        exportProcessContract.setPartyAClientName(customer.getCustomerName());
+        exportProcessContract.setPartyA(partyA);
 
-        public GroupedCustomer(Long customerId, String customerName) {
-            this.customerId = customerId;
-            this.customerName = customerName;
+        // 濉啓涔欐柟淇℃伅
+        ExportProcessContractVo.Customer partyB = new ExportProcessContractVo.Customer();
+        exportProcessContract.setPartyBClientName("澶╂触闃冲厜褰╁嵃鑲′唤鏈夐檺鍏徃");
+        partyB.setBankName("鍐滆澶╂触姝︽竻寮�鍙戝尯鏀");
+        partyB.setBankCode("02061601040014681");
+        partyB.setTaxpayerIdentificationNumber("91120000562687393p");
+        partyB.setAddress("澶╂触姝︽竻鍖哄紑鍙戝尯娉夊窞鍖楄矾29鍙�");
+        partyB.setFax("022-82126666");
+        partyB.setPostCode("301700");
+        exportProcessContract.setPartyB(partyB);
+
+        // 濉啓鍟嗗搧淇℃伅
+        final BigDecimal[] totalAmount = {BigDecimal.ZERO}; // 鎬婚噾棰�
+        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
+        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId());
+        productWrapper.eq(SalesLedgerProduct::getType, 1);
+        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
+        List<ExportProcessContractVo.SaleProduct> productList = products.stream().map(it -> {
+            ExportProcessContractVo.SaleProduct saleProduct = BeanUtil.copyProperties(it, ExportProcessContractVo.SaleProduct.class);
+            // 璁$畻鎬讳环鏍�
+            totalAmount[0] = totalAmount[0].add(Optional.ofNullable(saleProduct.getTaxInclusiveTotalPrice()).orElse(BigDecimal.ZERO));
+            return saleProduct;
+        }).collect(Collectors.toList());
+        // 绗竴涓缃� 鍚堝悓缂栧彿
+        if (!productList.isEmpty()) {
+            productList.get(0).setSalesContractNo(salesLedger.getSalesContractNo());
+        }
+        // 鏌ョ湅绋庣巼 鐞嗚涓婄◣鐜囧崟涓�锛屽鏋滃绋庣巼涓虹┖
+        Map<BigDecimal, Long> rateMap = productList.stream().map(product -> product.getTaxRate()).filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+        String taxRateStr = rateMap.size() == 1 ? rateMap.keySet().iterator().next().toString() + " %" : "";
+        exportProcessContract.setTaxRate(taxRateStr);
+        exportProcessContract.setSaleProducts(productList);// 鍟嗗搧淇℃伅
+        // 璁剧疆澶у啓鐨勬�讳环鏍�
+        exportProcessContract.setTotalAmountZh(Convert.digitToChinese(totalAmount[0].doubleValue()));
+
+        exportProcessContractToWord(exportProcessContract);
+    }
+
+    @SneakyThrows
+    private void exportProcessContractToWord(@NotNull ExportProcessContractVo exportProcessContract){
+        // 纭繚 saleProducts 涓嶄负 null
+        if (exportProcessContract.getSaleProducts() == null) {
+            exportProcessContract.setSaleProducts(new ArrayList<>());
         }
 
-        public void addAmount(BigDecimal amount) {
-            if (amount != null) {
-                this.totalAmount = this.totalAmount.add(amount);
-            }
-        }
+        // 妯℃澘杈撳叆娴�
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/contract_tmp.docx");
+        Assert.isTrue(inputStream != null, "妯℃澘涓嶅瓨鍦�");
 
-        public Long getCustomerId() {
-            return customerId;
-        }
+        // 杞� Map
+        Map<String, Object> dataMap = BeanUtil.beanToMap(exportProcessContract);
 
-        public String getCustomerName() {
-            return customerName;
-        }
+        // 缁戝畾寰幆绛栫暐
+        Configure configure = Configure.builder()
+                .bind("saleProducts", new LoopRowTableRenderPolicy())
+                .build();
 
-        public BigDecimal getTotalAmount() {
-            return totalAmount;
-        }
+        // 娓叉煋妯℃澘
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure)
+                .render(dataMap);
+//        template.write(FileUtil.getOutputStream("/Users/ONEX/Downloads/a.docx"));
+
+        // 杈撳嚭鍒版祻瑙堝櫒
+        HttpServletResponse response =
+                ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
+                        .getResponse();
+        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        response.setHeader("Content-Disposition", "attachment;filename="+ StrUtil.format("{}-{}",exportProcessContract.getPartyAClientName(),exportProcessContract.getCreateTime()) +"鍚堝悓.docx");
+
+        template.write(response.getOutputStream());
+        template.close();
+        response.flushBuffer();
     }
 
     /**
@@ -636,7 +684,7 @@
             // 4. 澶勭悊瀛愯〃鏁版嵁
             List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
             if (productList != null && !productList.isEmpty()) {
-                handleSalesLedgerProducts(salesLedger.getId(), productList, salesLedgerDto.getType());
+                handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
                 updateMainContractAmount(
                         salesLedger.getId(),
                         productList,
@@ -655,8 +703,6 @@
             throw new BaseException("鏂囦欢杩佺Щ澶辫触: " + e.getMessage());
         }
     }
-
-    // 鏂囦欢杩佺Щ鏂规硶
 
     /**
      * 灏嗕复鏃舵枃浠惰縼绉诲埌姝e紡鐩綍
@@ -733,8 +779,10 @@
         }
     }
 
+    // 鏂囦欢杩佺Щ鏂规硶
 
-    private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) {
+    @Override
+    public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) {
         // 鎸塈D鍒嗙粍锛屽尯鍒嗘柊澧炲拰鏇存柊鐨勮褰�
         Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
                 .peek(p -> p.setSalesLedgerId(salesLedgerId))
@@ -746,14 +794,14 @@
         // 鎵ц鏇存柊鎿嶄綔
         if (!updateList.isEmpty()) {
             for (SalesLedgerProduct product : updateList) {
-                product.setType(type);
+                product.setType(type.getCode());
                 salesLedgerProductMapper.updateById(product);
             }
         }
         // 鎵ц鎻掑叆鎿嶄綔
         if (!insertList.isEmpty()) {
             for (SalesLedgerProduct salesLedgerProduct : insertList) {
-                salesLedgerProduct.setType(type);
+                salesLedgerProduct.setType(type.getCode());
                 salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
                 salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
                 salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
@@ -873,4 +921,34 @@
             throw new RuntimeException("鍔ㄦ�佹洿鏂颁富琛ㄩ噾棰濆け璐�", e);
         }
     }
+
+    // 鍐呴儴绫荤敤浜庡瓨鍌ㄨ仛鍚堢粨鏋�
+    private static class GroupedCustomer {
+        private final Long customerId;
+        private final String customerName;
+        private BigDecimal totalAmount = BigDecimal.ZERO;
+
+        public GroupedCustomer(Long customerId, String customerName) {
+            this.customerId = customerId;
+            this.customerName = customerName;
+        }
+
+        public void addAmount(BigDecimal amount) {
+            if (amount != null) {
+                this.totalAmount = this.totalAmount.add(amount);
+            }
+        }
+
+        public Long getCustomerId() {
+            return customerId;
+        }
+
+        public String getCustomerName() {
+            return customerName;
+        }
+
+        public BigDecimal getTotalAmount() {
+            return totalAmount;
+        }
+    }
 }

--
Gitblit v1.9.3