Преглед изворни кода

Merge remote-tracking branch 'origin/main'

lishiqiang пре 1 недеља
родитељ
комит
8ec2f0f336
12 измењених фајлова са 294 додато и 115 уклоњено
  1. 4 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyagestock/vo/VoyageStockBaseVO.java
  2. 2 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyagestockdistributeNew/vo/QueryCanSelectRoomListNewReqVO.java
  3. 5 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/dataobject/voyagestock/VoyageStockDO.java
  4. 2 1
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/mysql/voyagestock/VoyageStockMapper.java
  5. 21 4
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyagestockdistribute/VoyageStockDistributeNewServiceImpl.java
  6. 49 1
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/order/OtcTradeOrderController.java
  7. 2 1
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/OtcTradeOrderService.java
  8. 1 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/AppOtcTradeOrderServiceImpl.java
  9. 207 107
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/OtcTradeOrderServiceImpl.java
  10. 1 1
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeOrderMapper.xml
  11. BIN
      ship-module-trade/ship-module-trade-biz/src/main/resources/templates/confirmation_template.xlsx
  12. BIN
      ship-module-trade/ship-module-trade-biz/src/main/resources/templates/logo.png

+ 4 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyagestock/vo/VoyageStockBaseVO.java

@@ -70,4 +70,8 @@ public class VoyageStockBaseVO {
     @Schema(description = "分享房间数")
     @ExcelProperty("分享房间数")
     private BigDecimal shareNum;
+
+    private Long routeId;
+
+    private Integer direction;
 }

+ 2 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyagestockdistributeNew/vo/QueryCanSelectRoomListNewReqVO.java

@@ -19,6 +19,8 @@ public class QueryCanSelectRoomListNewReqVO {
     private Long distributorId;
     @Schema(description = "门店ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Long storeId;
+    @Schema(description = "订单ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1024")
+    private Long orderId;
     @Schema(description = "房型ID+'_'+楼层号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private List<String> roomModelIdFloorList;
 

+ 5 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/dataobject/voyagestock/VoyageStockDO.java

@@ -93,4 +93,9 @@ public class VoyageStockDO extends TenantBaseDO {
      */
     private BigDecimal shareNum;
 
+    @TableField(exist = false)
+    private Long routeId;
+    @TableField(exist = false)
+    private Integer direction;
+
 }

+ 2 - 1
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/mysql/voyagestock/VoyageStockMapper.java

@@ -33,7 +33,8 @@ public interface VoyageStockMapper extends BaseMapperX<VoyageStockDO> {
                 .orderByAsc(VoyageStockDO::getVoyageId));*/
         MPJLambdaWrapperX<VoyageStockDO> wrapperX = new MPJLambdaWrapperX<>();
         wrapperX.selectAll(VoyageStockDO.class);
-        wrapperX.leftJoin(VoyageDO.class, VoyageDO::getId, VoyageStockDO::getVoyageId);
+        wrapperX.leftJoin(VoyageDO.class,"pv", VoyageDO::getId, VoyageStockDO::getVoyageId)
+                .selectAs("pv.route_id", VoyageStockDO::getRouteId);
         wrapperX.likeIfPresent(VoyageStockDO::getVoyageName, reqVO.getVoyageName())
                 .eqIfPresent(VoyageStockDO::getShipId, reqVO.getShipId())
                 .inIfPresent(VoyageStockDO::getVoyageId, reqVO.getVoyageIds())

+ 21 - 4
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyagestockdistribute/VoyageStockDistributeNewServiceImpl.java

@@ -2,7 +2,9 @@ package com.yc.ship.module.product.service.voyagestockdistribute;
 
 import com.yc.ship.framework.common.pojo.PageResult;
 import com.yc.ship.framework.common.util.collection.CollectionUtils;
+import com.yc.ship.framework.common.util.collection.MapUtils;
 import com.yc.ship.framework.common.util.object.BeanUtils;
+import com.yc.ship.module.product.controller.admin.voyage.vo.VoyageRespVO;
 import com.yc.ship.module.product.controller.admin.voyagestock.vo.VoyageStockPageReqVO;
 import com.yc.ship.module.product.controller.admin.voyagestock.vo.VoyageStockRespVO;
 import com.yc.ship.module.product.controller.admin.voyagestockdistributeNew.vo.*;
@@ -21,7 +23,9 @@ import com.yc.ship.module.product.service.voyagestockdetail.VoyageStockDetailSer
 import com.yc.ship.module.resource.api.room.RoomApi;
 import com.yc.ship.module.resource.api.room.dto.RoomRespDTO;
 import com.yc.ship.module.resource.dal.dataobject.roommodel.ResourceRoomModelDO;
+import com.yc.ship.module.resource.dal.dataobject.route.ResourceRouteDO;
 import com.yc.ship.module.resource.service.roommodel.ResourceRoomModelService;
+import com.yc.ship.module.resource.service.route.ResourceRouteService;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
@@ -31,10 +35,7 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -75,6 +76,9 @@ public class VoyageStockDistributeNewServiceImpl implements VoyageStockDistribut
     @Resource
     private VoyageStockRoomUsedMapper voyageStockRoomUsedMapper;
 
+    @Resource
+    private ResourceRouteService routeService;
+
 
 
     @Override
@@ -196,6 +200,9 @@ public class VoyageStockDistributeNewServiceImpl implements VoyageStockDistribut
         }
         //获取完全被使用的房间
         List<VoyageStockRoomUsedDO> allUsedList = voyageStockRoomUsedMapper.selectAllUsedList(reqVO.getVoyageId());
+        allUsedList = allUsedList.stream().filter(item -> {
+            return !Objects.equals(item.getOrderId(), reqVO.getOrderId());
+        }).collect(Collectors.toList());
         List<Long> allUserRoomId = CollectionUtils.convertList(allUsedList, VoyageStockRoomUsedDO::getRoomId);
         //过滤掉完全被使用的房间
         List<Long> canSelectRoomIds = roomIds.stream().filter(item -> !allUserRoomId.contains(item)).collect(Collectors.toList());
@@ -218,6 +225,9 @@ public class VoyageStockDistributeNewServiceImpl implements VoyageStockDistribut
         VoyageStockPageReqVO pageParams = BeanUtils.toBean(reqVO, VoyageStockPageReqVO.class);
         PageResult<VoyageStockRespVO> voyageStockPage = voyageStockService.getVoyageStockPage(pageParams);
         List<VoyageStockRespVO> list = voyageStockPage.getList();
+        List<Long> routeIds = CollectionUtils.convertList(list, VoyageStockRespVO::getRouteId);
+        List<ResourceRouteDO> routeList = routeService.getList(routeIds);
+        Map<Long, Integer> routeDoMap = CollectionUtils.convertMap(routeList, ResourceRouteDO::getId, ResourceRouteDO::getDirection);
         List<Long> voyageIds = CollectionUtils.convertList(list, VoyageStockRespVO::getVoyageId);
         List<VoyageStockDistributeNewPageRespVO> distributeNewList = voyageStockDistributeNewMapper.selectGroupList(voyageIds, reqVO);
         Map<Long, BigDecimal> idNumMap = CollectionUtils.convertMap(distributeNewList, VoyageStockDistributeNewPageRespVO::getVoyageId, VoyageStockDistributeNewPageRespVO::getNum);
@@ -225,6 +235,13 @@ public class VoyageStockDistributeNewServiceImpl implements VoyageStockDistribut
         List<VoyageStockDistributeNewPageRespVO> resultList = new ArrayList<>();
 
         list.forEach(item -> {
+
+            MapUtils.findAndThen(routeDoMap, item.getRouteId(), direction -> item.setDirection(direction));
+            if(routeDoMap.get(item.getRouteId()) == 2) {
+                item.setVoyageName(item.getVoyageName()+"-下水");
+            }else {
+                item.setVoyageName(item.getVoyageName()+"-上水");
+            }
             BigDecimal num = idNumMap.get(item.getVoyageId());
             BigDecimal roomModelNum = idRoomModelNumMap.get(item.getVoyageId());
             // 根据航次查询是否有营销政策(暂时包含当天)

+ 49 - 1
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/order/OtcTradeOrderController.java

@@ -46,6 +46,8 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.IOUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -60,6 +62,7 @@ import javax.annotation.security.PermitAll;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
@@ -658,7 +661,52 @@ public class OtcTradeOrderController {
         response.setContentType("application/vnd.ms-excel");
         response.setHeader("Content-Disposition", "attachment; filename=" + tempFile.getName());
         InputStream is = Files.newInputStream(tempFile.toPath());
-        IOUtils.copy(is, response.getOutputStream());
+
+        Workbook workbook = new XSSFWorkbook(is);
+        Sheet sheet = workbook.getSheetAt(0);
+
+        InputStream logo = getClass().getClassLoader().getResourceAsStream("templates/logo.png");
+        byte[] bytes = org.apache.poi.util.IOUtils.toByteArray(logo);
+        // 读取图片文件到byte数组
+        int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
+        logo.close();
+
+        // 创建drawing patriarch和anchor对象
+        CreationHelper helper = workbook.getCreationHelper();
+        Drawing drawing = sheet.createDrawingPatriarch();
+        ClientAnchor anchor = helper.createClientAnchor();
+
+        int lastRowNum = sheet.getLastRowNum();
+        int rowNum = 0;
+        for(int i = 0; i <= lastRowNum; i++) {
+            Row row = sheet.getRow(i);
+            if(row != null) {
+                Cell cell = row.getCell(0);
+                if(cell != null) {
+                    if(cell.getStringCellValue().equals("a")) {
+                        rowNum = i;
+                        break;
+                    }
+                }
+            }
+        }
+        // 设置图片位置和大小(例如,放在A1单元格)
+        anchor.setCol1(6); // Column A
+        anchor.setRow1(rowNum); // Row 1
+        anchor.setDx1(10); // 水平偏移量(相对于锚点的像素)
+        anchor.setDy1(10);
+
+        // 创建图片对象并设置到workbook中
+        Picture pict = drawing.createPicture(anchor, pictureIdx);
+        pict.resize(); // 根据anchor调整图片大小
+
+        // 关闭流并保存文件
+        FileOutputStream out = new FileOutputStream(tempFile.toPath().toString());
+        workbook.write(out);
+        out.close();
+        workbook.close();
+        InputStream is1 = Files.newInputStream(tempFile.toPath());
+        IOUtils.copy(is1, response.getOutputStream());
     }
 
 

+ 2 - 1
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/OtcTradeOrderService.java

@@ -21,6 +21,7 @@ import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailBaseDO;
 
 import javax.validation.Valid;
 import java.io.File;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.List;
 
@@ -143,7 +144,7 @@ public interface OtcTradeOrderService {
     /**
      * 生成确认单
      */
-    File createConfirmaction(Long id, Double totalMoney);
+    File createConfirmaction(Long id, Double totalMoney) throws IOException;
 
     CommonResult<?> orderRead(Long orderId);
 

+ 1 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/AppOtcTradeOrderServiceImpl.java

@@ -309,6 +309,7 @@ public class AppOtcTradeOrderServiceImpl implements AppOtcTradeOrderService {
         visitor.setYczz(tradeVistorReqVO.getYichang());
         visitor.setCqzz(tradeVistorReqVO.getChongqing());
         visitor.setRoomId(tradeVistorReqVO.getRoomId());
+        visitor.setInitRoomId(tradeVistorReqVO.getRoomId());
         visitor.setNationality(tradeVistorReqVO.getNationality());
         visitor.setGender(tradeVistorReqVO.getGender());
         visitor.setBirthday(tradeVistorReqVO.getBirthday());

+ 207 - 107
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/OtcTradeOrderServiceImpl.java

@@ -8,7 +8,10 @@ import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.EasyExcelFactory;
 import com.alibaba.excel.ExcelWriter;
 import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.metadata.data.ImageData;
+import com.alibaba.excel.metadata.data.WriteCellData;
 import com.alibaba.excel.util.DateUtils;
+import com.alibaba.excel.util.FileUtils;
 import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
 import com.alibaba.excel.write.merge.AbstractMergeStrategy;
 import com.alibaba.excel.write.metadata.WriteSheet;
@@ -31,6 +34,7 @@ import com.yc.ship.framework.common.util.collection.CollectionUtils;
 import com.yc.ship.framework.common.util.object.BeanUtils;
 import com.yc.ship.framework.common.util.object.ObjectUtils;
 import com.yc.ship.framework.dict.core.DictFrameworkUtils;
+import com.yc.ship.framework.excel.core.merge.MergeStrategy;
 import com.yc.ship.framework.ip.core.utils.AreaUtils;
 import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
 import com.yc.ship.framework.security.core.LoginUser;
@@ -136,9 +140,13 @@ import com.yc.ship.module.trade.utils.AgencyAuthUtils;
 import com.yc.ship.module.trade.utils.excel.ExcelStyleHandler;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.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.ss.util.RegionUtil;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jetbrains.annotations.NotNull;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
@@ -146,9 +154,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.io.File;
-import java.io.InputStream;
+import java.io.*;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
@@ -2405,10 +2413,16 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
                 tradeOrderBindDO.setRemark("提交营销政策");
                 shipTradeOrderCreateReqVO.setTradeOrderBindDO(tradeOrderBindDO);
             }
+            List<TradeOrderRoomModelVO> roomModelList = createVO.getRoomModelList();
+            Map<String, TradeOrderRoomModelVO> roomMap = CollectionUtils.convertMap(roomModelList, TradeOrderRoomModelVO::getRoomIndexId);
             ShipTradeOrderCreateReqVO.OrderItem orderItem = new ShipTradeOrderCreateReqVO.OrderItem();
             List<ShipTradeOrderCreateReqVO.OrderDetail> detailList = new ArrayList<>();
             ShipTradeOrderCreateReqVO.OrderDetail orderDetail = new ShipTradeOrderCreateReqVO.OrderDetail();
             for (TradeVistorReqVO tradeVistorReqVO : createVO.getTourist()) {
+                TradeOrderRoomModelVO roomModelVO = roomMap.get(tradeVistorReqVO.getRoomIndexId());
+                if(Objects.nonNull(roomModelVO) && Objects.nonNull(roomModelVO.getRoomId())) {
+                    tradeVistorReqVO.setRoomId(String.valueOf(roomModelVO.getRoomId()));
+                }
                 List<ShipTradeOrderCreateReqVO.Visitor> visitorList = new ArrayList<>();
                 ShipTradeOrderCreateReqVO.OrderDetail visitorDetailId = new ShipTradeOrderCreateReqVO.OrderDetail();
                 //BeanUtils.copyProperties(orderDetail, ShipTradeOrderCreateReqVO.OrderDetail.class);
@@ -2439,6 +2453,10 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
                 List<ShipTradeOrderCreateReqVO.Visitor> visitorList1 = new ArrayList<>();
                 for (String touristId : tradeSpuReqVO.getTourist()) {
                     TradeVistorReqVO tradeVistorReqVO = createVO.getTourist().stream().filter(v -> v.getId().equals(touristId)).findFirst().orElseGet(TradeVistorReqVO::new);
+                    TradeOrderRoomModelVO roomModelVO = roomMap.get(tradeVistorReqVO.getRoomIndexId());
+                    if(Objects.nonNull(roomModelVO) && Objects.nonNull(roomModelVO.getRoomId())) {
+                        tradeVistorReqVO.setRoomId(String.valueOf(roomModelVO.getRoomId()));
+                    }
                     ShipTradeOrderCreateReqVO.Visitor visitor = getVisitor1(tradeVistorReqVO);
                     visitorList1.add(visitor);
                     BigDecimal price = tradeSpuReqVO.getPrice() == null ? BigDecimal.ZERO : tradeSpuReqVO.getPrice();
@@ -2484,7 +2502,7 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
 
             // 创建订单房型数据
             List<TradeOrderRoomModelDO> tradeOrderRoomDOList = new ArrayList<>();
-            List<TradeOrderRoomModelVO> roomModelList = createVO.getRoomModelList();
+
             roomModelList.forEach(roomModel -> {
                 TradeOrderRoomModelDO tradeOrderRoomDO = BeanUtils.toBean(roomModel, TradeOrderRoomModelDO.class);
                 tradeOrderRoomDO.setOrderId(orderId);
@@ -2588,6 +2606,7 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
         visitor.setYczz(tradeVistorReqVO.getYichang());
         visitor.setCqzz(tradeVistorReqVO.getChongqing());
         visitor.setRoomId(tradeVistorReqVO.getRoomId());
+        visitor.setInitRoomId(tradeVistorReqVO.getRoomId());
         visitor.setNationality(tradeVistorReqVO.getNationality());
         visitor.setGender(tradeVistorReqVO.getGender());
         visitor.setBirthday(tradeVistorReqVO.getBirthday());
@@ -2706,7 +2725,13 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
             List<ShipTradeOrderCreateReqVO.OrderDetail> detailList = new ArrayList<>();
             ShipTradeOrderCreateReqVO.OrderDetail orderDetail = new ShipTradeOrderCreateReqVO.OrderDetail();
             // 处理游客信息
+            List<TradeOrderRoomModelVO> roomModelList = createVO.getRoomModelList();
+            Map<String, TradeOrderRoomModelVO> roomMap = CollectionUtils.convertMap(roomModelList, TradeOrderRoomModelVO::getRoomIndexId);
             for (TradeVistorReqVO tradeVistorReqVO : createVO.getTourist()) {
+                TradeOrderRoomModelVO roomModelVO = roomMap.get(tradeVistorReqVO.getRoomIndexId());
+                if(Objects.nonNull(roomModelVO) && Objects.nonNull(roomModelVO.getRoomId())) {
+                    tradeVistorReqVO.setRoomId(String.valueOf(roomModelVO.getRoomId()));
+                }
                 List<ShipTradeOrderCreateReqVO.Visitor> visitorList = new ArrayList<>();
                 ShipTradeOrderCreateReqVO.OrderDetail visitorDetailId = new ShipTradeOrderCreateReqVO.OrderDetail();
                 String visitorId = tradeVistorReqVO.getId();
@@ -2742,6 +2767,10 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
                 List<ShipTradeOrderCreateReqVO.Visitor> visitorList1 = new ArrayList<>();
                 for (String touristId : tradeSpuReqVO.getTourist()) {
                     TradeVistorReqVO tradeVistorReqVO = createVO.getTourist().stream().filter(v -> v.getId().equals(touristId)).findFirst().orElseGet(TradeVistorReqVO::new);
+                    TradeOrderRoomModelVO roomModelVO = roomMap.get(tradeVistorReqVO.getRoomIndexId());
+                    if(Objects.nonNull(roomModelVO) && Objects.nonNull(roomModelVO.getRoomId())) {
+                        tradeVistorReqVO.setRoomId(String.valueOf(roomModelVO.getRoomId()));
+                    }
                     ShipTradeOrderCreateReqVO.Visitor visitor = getVisitor1(tradeVistorReqVO);
                     visitorList1.add(visitor);
                     BigDecimal price = tradeSpuReqVO.getPrice() == null ? BigDecimal.ZERO : tradeSpuReqVO.getPrice();
@@ -3417,6 +3446,40 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
         TradeOrderTotalVO summary = BeanUtils.toBean(tradeOrderTotalDO, TradeOrderTotalVO.class);
         orderRespNewVO.setSummary(summary);
 
+        // 计算领队单价
+        Integer leaderTotalNum = summary.getLeaderTotalNum();
+        if(leaderTotalNum != null && leaderTotalNum > 0) {
+            BigDecimal leaderPrice = summary.getLeaderAmount().divide(new BigDecimal(leaderTotalNum), 2, RoundingMode.HALF_UP);
+            countryList.stream().forEach(item -> {
+                if(Objects.equals(item.getType(), "leader")) {
+                    item.setActualPrice(leaderPrice);
+                }
+            });
+        }
+        // 计算陪同单价
+        Integer withTotalNum = summary.getWithTotalNum();
+        if(withTotalNum != null && withTotalNum > 0) {
+            BigDecimal withPrice = summary.getWithAmount().divide(new BigDecimal(withTotalNum), 2, RoundingMode.HALF_UP);
+            countryList.stream().forEach(item -> {
+                if(Objects.equals(item.getType(), "with")) {
+                    item.setActualPrice(withPrice);
+                }
+            });
+        }
+        // 添加16免1
+        Integer freeNum = summary.getFreeNum();
+        if(freeNum != null && freeNum > 0) {
+            BigDecimal freePrice = summary.getFreeAmount().divide(new BigDecimal(freeNum), 2, RoundingMode.HALF_UP);
+            TradeOrderConfirmationCountryRespVO countryRespVO = new TradeOrderConfirmationCountryRespVO();
+            countryRespVO.setActualPrice(freePrice.negate());
+            countryRespVO.setNum(freeNum);
+            countryRespVO.setType("free");
+            countryRespVO.setRoomModelName("16免1");
+            countryRespVO.setRoomModelShortName("16免1");
+            countryRespVO.setNationalityName("-");
+            countryRespVO.setFloor(0);
+            countryList.add(countryRespVO);
+        }
         //设置游轮航次信息
         VoyageDO voyageDO = voyageService.getVoyage(tradeOrderDO.getVoyageId());
         orderRespNewVO.setVoyage(BeanUtils.toBean(voyageDO, VoyageRespVO.class));
@@ -3433,112 +3496,149 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
 
     @Override
     public File createConfirmaction(Long id, Double totalMoney) {
-        TradeOrderConfirmationVO orderConfirmation = getOrderConfirmation(id);
-        InputStream template = getClass().getClassLoader().getResourceAsStream("templates/confirmation_template.xlsx");
-        String tmpFile = "/tmp/" + orderConfirmation.getId() + ".xlsx";
-        ExcelWriter excelWriter = EasyExcel.write(tmpFile).withTemplate(template).build();
-        ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcelFactory.writerSheet();
-        // 需要合并单元格的writeSheet
-        WriteSheet writeSheet = excelWriterSheetBuilder.registerWriteHandler(new MergeStrategy()).build();
-        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
-
-        // 订单信息
-        Map<String, Object> orderData = new HashMap<>();
-        orderData.put("orderNo", orderConfirmation.getOrderNo());
-        orderData.put("shipName", orderConfirmation.getShipName());
-        orderData.put("shipNameEn", orderConfirmation.getShipNameEn());
-        orderData.put("groupNo", orderConfirmation.getGroupNo());
-        orderData.put("sourceName", orderConfirmation.getSourceName());
-        orderData.put("linkMan", orderConfirmation.getLinkMan());
-        orderData.put("linkMobile", orderConfirmation.getLinkMobile());
-        orderData.put("amount", orderConfirmation.getAmount());
-        orderData.put("remark", orderConfirmation.getRemark());
-
-        VoyageRespVO voyage = orderConfirmation.getVoyage();
-        //此处改为订单号最后的序号,如CJXLY-20260526-YC-13订单,登船序号应为13
-        String[] split = orderConfirmation.getOrderNo().split("-");
-        String split1 = split[split.length - 1];
-        orderData.put("voyageCode", split1);
-
-        orderData.put("boardingTime", DateUtil.format(Date.from(voyage.getBoardingTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-        orderData.put("startTime", DateUtil.format(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-        orderData.put("leaveTime", DateUtil.format(Date.from(voyage.getLeaveTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-
-        ResourceRouteDO resourceRouteDO = orderConfirmation.getResourceRouteDO();
-        String resourceRoute = "重庆-宜昌";
-        String resourceRouteEn = "Chongqing-Yichang";
-        if (resourceRouteDO != null && resourceRouteDO.getDirection() != null && resourceRouteDO.getDirection() == 1) {
-            resourceRoute = "宜昌-重庆";
-            resourceRouteEn = "Yichang-Chongqing";
-        }
-        orderData.put("resourceRoute", resourceRoute);
-        orderData.put("resourceRouteEn", resourceRouteEn);
-
-        // 房型信息
-        List<Map<String, Object>> roomData = new ArrayList<>();
-        List<TradeOrderConfirmationCountryRespVO> countryList = orderConfirmation.getCountryList();
-        if (countryList != null) {
-            countryList.forEach(item -> {
-                String roomModelName = item.getRoomModelName();
-                if (item.getFloor() == null) {
-                    if ("leader".equals(item.getType())) {
-                        roomModelName = roomModelName + "(领队)";
-                    } else if ("with".equals(item.getType())) {
-                        roomModelName = roomModelName + "(陪同)";
+        try {
+            TradeOrderConfirmationVO orderConfirmation = getOrderConfirmation(id);
+            InputStream template = getClass().getClassLoader().getResourceAsStream("templates/confirmation_template.xlsx");
+            String tmpFile = "/tmp/" + orderConfirmation.getId() + ".xlsx";
+            ExcelWriter excelWriter = EasyExcel.write(tmpFile).withTemplate(template).build();
+            ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcelFactory.writerSheet();
+            // 需要合并单元格的writeSheet
+            WriteSheet writeSheet = excelWriterSheetBuilder.registerWriteHandler(new MergeStrategy()).build();
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
+
+            // 订单信息
+            Map<String, Object> orderData = new HashMap<>();
+            orderData.put("orderNo", orderConfirmation.getOrderNo());
+            orderData.put("shipName", orderConfirmation.getShipName());
+            orderData.put("shipNameEn", orderConfirmation.getShipNameEn());
+            orderData.put("groupNo", orderConfirmation.getGroupNo());
+            orderData.put("sourceName", orderConfirmation.getSourceName());
+            orderData.put("linkMan", orderConfirmation.getLinkMan());
+            orderData.put("linkMobile", orderConfirmation.getLinkMobile());
+            orderData.put("amount", orderConfirmation.getAmount());
+            orderData.put("remark", orderConfirmation.getRemark());
+
+            VoyageRespVO voyage = orderConfirmation.getVoyage();
+            //此处改为订单号最后的序号,如CJXLY-20260526-YC-13订单,登船序号应为13
+            String[] split = orderConfirmation.getOrderNo().split("-");
+            String split1 = split[split.length - 1];
+            orderData.put("voyageCode", split1);
+
+            orderData.put("boardingTime", DateUtil.format(Date.from(voyage.getBoardingTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+            orderData.put("startTime", DateUtil.format(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+            orderData.put("leaveTime", DateUtil.format(Date.from(voyage.getLeaveTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+
+            ResourceRouteDO resourceRouteDO = orderConfirmation.getResourceRouteDO();
+            String resourceRoute = "重庆-宜昌";
+            String resourceRouteEn = "Chongqing-Yichang";
+            if (resourceRouteDO != null && resourceRouteDO.getDirection() != null && resourceRouteDO.getDirection() == 1) {
+                resourceRoute = "宜昌-重庆";
+                resourceRouteEn = "Yichang-Chongqing";
+            }
+            orderData.put("resourceRoute", resourceRoute);
+            orderData.put("resourceRouteEn", resourceRouteEn);
+
+            // 房型信息
+            List<Map<String, Object>> roomData = new ArrayList<>();
+            List<TradeOrderConfirmationCountryRespVO> countryList = orderConfirmation.getCountryList();
+            if (countryList != null) {
+                countryList.forEach(item -> {
+                    String roomModelName = item.getRoomModelName();
+                    if (item.getFloor() == null) {
+                        if ("leader".equals(item.getType())) {
+                            roomModelName = roomModelName + "(领队)";
+                        } else if ("with".equals(item.getType())) {
+                            roomModelName = roomModelName + "(陪同)";
+                        }
+                    } else {
+                        roomModelName = roomModelName + "(" + item.getFloor() + "F)";
                     }
-                } else {
-                    roomModelName = roomModelName + "(" + item.getFloor() + "F)";
-                }
-                Map<String, Object> room = new HashMap<>();
-                room.put("roomModelName", roomModelName);
-                room.put("countryName", item.getNationalityName());
-                room.put("personTypeDes", getPersonTypeDes1(item.getType()));
-                room.put("personTypeDesEn", getPersonTypeDesEn1(item.getType()));
-                room.put("qty", item.getNum());
-                room.put("price", item.getActualPrice());
-                room.put("realMoney", item.getActualPrice().multiply(new BigDecimal(item.getNum())));
-                roomData.add(room);
-            });
+                    Map<String, Object> room = new HashMap<>();
+                    room.put("roomModelName", roomModelName);
+                    room.put("countryName", item.getNationalityName());
+                    room.put("personTypeDes", getPersonTypeDes1(item.getType()));
+                    room.put("personTypeDesEn", getPersonTypeDesEn1(item.getType()));
+                    room.put("qty", item.getNum());
+                    room.put("price", item.getActualPrice());
+                    room.put("realMoney", item.getActualPrice().multiply(new BigDecimal(item.getNum())));
+                    roomData.add(room);
+                });
+            }
+            orderData.put("countryDes", orderConfirmation.getCountryDesc());
+            orderData.put("useRoomTotalDesc", orderConfirmation.getUseRoomTotalDesc());
+            TradeOrderTotalVO summary = orderConfirmation.getSummary();
+            if (summary != null) {
+                orderData.put("roomModelDes", summary.getUseRoomTotalNum());
+            } else {
+                orderData.put("roomModelDes", 0);
+            }
+
+            orderData.put("totalMoney", totalMoney);
+            orderData.put("creatorName", orderConfirmation.getCreatorName());
+            orderData.put("auditorName", orderConfirmation.getAuditorName());
+            orderData.put("firstDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(orderConfirmation.getCreateTime().atZone(ZoneOffset.ofHours(8)).toInstant()), 7), "yyyy-MM-dd"));
+            orderData.put("lastDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), -21), "yyyy-MM-dd"));
+            orderData.put("today", DateUtil.format(new Date(), "yyyy-MM-dd"));
+
+            // 游客信息
+            List<Map<String, Object>> tradeVisitorData = new ArrayList<>();
+            List<TradeVisitorDO> tradeVisitorList = orderConfirmation.getTradeVisitorList();
+            for (int i = 0; i < tradeVisitorList.size(); i++) {
+                Map<String, Object> item = new HashMap<>();
+                TradeVisitorDO tradeVisitorDO = tradeVisitorList.get(i);
+                item.put("index", String.valueOf((i + 1)));
+                item.put("name", StringUtils.isEmpty(tradeVisitorDO.getName()) ? "" : tradeVisitorDO.getName());
+                item.put("nationality", StringUtils.isEmpty(tradeVisitorDO.getNationalityName()) ? "" : tradeVisitorDO.getNationalityName());
+                item.put("gender", (tradeVisitorDO.getGender() == null || tradeVisitorDO.getGender() == 0) ? "女" : "男");
+                item.put("dob", StringUtils.isEmpty(tradeVisitorDO.getBirthday()) ? "" : tradeVisitorDO.getBirthday());
+                item.put("credentialTypeName", DictFrameworkUtils.getDictDataLabel(DictTypeConstants.VISITOR_CREDENTIAL_TYPE, tradeVisitorDO.getCredentialType()));
+                item.put("idno", StringUtils.isEmpty(tradeVisitorDO.getCredentialNo()) ? "" : tradeVisitorDO.getCredentialNo());
+                tradeVisitorData.add(item);
+            }
+
+            // 填充单条数据
+            excelWriter.fill(orderData, writeSheet);
+            // 填充列表数据
+            excelWriter.fill(new FillWrapper("room", roomData), fillConfig, writeSheet);
+            excelWriter.fill(new FillWrapper("visitor", tradeVisitorData), fillConfig, writeSheet);
+            excelWriter.finish();
+            File file = new File(tmpFile);
+//            drawImage(file);
+            return file;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
         }
-        orderData.put("countryDes", orderConfirmation.getCountryDesc());
-        orderData.put("useRoomTotalDesc", orderConfirmation.getUseRoomTotalDesc());
-        TradeOrderTotalVO summary = orderConfirmation.getSummary();
-        if (summary != null) {
-            orderData.put("roomModelDes", summary.getUseRoomTotalNum());
-        } else {
-            orderData.put("roomModelDes", 0);
-        }
-
-        orderData.put("totalMoney", totalMoney);
-        orderData.put("creatorName", orderConfirmation.getCreatorName());
-        orderData.put("auditorName", orderConfirmation.getAuditorName());
-        orderData.put("firstDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(orderConfirmation.getCreateTime().atZone(ZoneOffset.ofHours(8)).toInstant()), 7), "yyyy-MM-dd"));
-        orderData.put("lastDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), -21), "yyyy-MM-dd"));
-        orderData.put("today", DateUtil.format(new Date(), "yyyy-MM-dd"));
-
-        // 游客信息
-        List<Map<String, Object>> tradeVisitorData = new ArrayList<>();
-        List<TradeVisitorDO> tradeVisitorList = orderConfirmation.getTradeVisitorList();
-        for (int i = 0; i < tradeVisitorList.size(); i++) {
-            Map<String, Object> item = new HashMap<>();
-            TradeVisitorDO tradeVisitorDO = tradeVisitorList.get(i);
-            item.put("index", String.valueOf((i + 1)));
-            item.put("name", StringUtils.isEmpty(tradeVisitorDO.getName()) ? "" : tradeVisitorDO.getName());
-            item.put("nationality", StringUtils.isEmpty(tradeVisitorDO.getNationalityName()) ? "" : tradeVisitorDO.getNationalityName());
-            item.put("gender", (tradeVisitorDO.getGender() == null || tradeVisitorDO.getGender() == 0) ? "女" : "男");
-            item.put("dob", StringUtils.isEmpty(tradeVisitorDO.getBirthday()) ? "" : tradeVisitorDO.getBirthday());
-            item.put("credentialTypeName", DictFrameworkUtils.getDictDataLabel(DictTypeConstants.VISITOR_CREDENTIAL_TYPE, tradeVisitorDO.getCredentialType()));
-            item.put("idno", StringUtils.isEmpty(tradeVisitorDO.getCredentialNo()) ? "" : tradeVisitorDO.getCredentialNo());
-            tradeVisitorData.add(item);
-        }
-
-        // 填充单条数据
-        excelWriter.fill(orderData, writeSheet);
-        // 填充列表数据
-        excelWriter.fill(new FillWrapper("room", roomData), fillConfig, writeSheet);
-        excelWriter.fill(new FillWrapper("visitor", tradeVisitorData), fillConfig, writeSheet);
-        excelWriter.finish();
-        return new File(tmpFile);
+    }
+
+    public void drawImage(File excelFilePath) throws IOException, InvalidFormatException {
+        Workbook workbook = new XSSFWorkbook(excelFilePath);
+        Sheet sheet = workbook.getSheetAt(0);
+
+        InputStream logo = getClass().getClassLoader().getResourceAsStream("templates/logo.png");
+        byte[] bytes = IOUtils.toByteArray(logo);
+        // 读取图片文件到byte数组
+        int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
+        logo.close();
+
+        // 创建drawing patriarch和anchor对象
+        CreationHelper helper = workbook.getCreationHelper();
+        Drawing drawing = sheet.createDrawingPatriarch();
+        ClientAnchor anchor = helper.createClientAnchor();
+
+        int lastRowNum = sheet.getLastRowNum();
+        // 设置图片位置和大小(例如,放在A1单元格)
+        anchor.setCol1(5); // Column A
+        anchor.setRow1(lastRowNum); // Row 1
+
+        // 创建图片对象并设置到workbook中
+        Picture pict = drawing.createPicture(anchor, pictureIdx);
+        pict.resize(); // 根据anchor调整图片大小
+
+        // 关闭流并保存文件
+        FileOutputStream out = new FileOutputStream(excelFilePath);
+        workbook.write(out);
+        out.close();
+        workbook.close();
     }
 
     @Override

+ 1 - 1
ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeOrderMapper.xml

@@ -2522,7 +2522,7 @@
             t1.type,
             ifnull(t1.floor,'0') floor,
             count( t1.id ) num,
-            t2.actual_price actual_price
+            ifnull(t2.actual_price,0) actual_price
         FROM
             trade_visitor t1
                 LEFT JOIN trade_detail t2 ON t1.id = t2.visitor_id

BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/confirmation_template.xlsx


BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/logo.png