From 7bf754a7835d06f26240c4ca15bc5f83650de377 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 21 九月 2026 20:52:25 +0800
Subject: [PATCH] docs(api): 更新信托基金与代储台账及油品出库相关接口文档

---
 src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java |  246 +++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 218 insertions(+), 28 deletions(-)

diff --git a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
index 4763399..54337d8 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -4,29 +4,46 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
+import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
+import com.ruoyi.approve.pojo.ApprovalTemplate;
 import com.ruoyi.approve.pojo.ApproveProcess;
+import com.ruoyi.approve.service.ApprovalInstanceService;
 import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.other.service.impl.TempFileServiceImpl;
+import com.ruoyi.common.utils.OrderUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.procurementrecord.bean.vo.ShippingProductVo;
 import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.sales.dto.SalesLedgerProductDto;
+import com.ruoyi.sales.dto.SalesLedgerArrivalDto;
+import com.ruoyi.sales.dto.ShippingApproveDto;
 import com.ruoyi.sales.dto.ShippingInfoDto;
+import com.ruoyi.sales.dto.ShippingProductDetailDto;
+import com.ruoyi.sales.mapper.SalesLedgerArrivalMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.sales.mapper.ShippingProductDetailMapper;
 import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.sales.pojo.ShippingProductDetail;
 import com.ruoyi.sales.service.ShippingInfoService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @author :yys
@@ -37,21 +54,81 @@
 @RequiredArgsConstructor
 public class ShippingInfoServiceImpl extends ServiceImpl<ShippingInfoMapper, ShippingInfo> implements ShippingInfoService {
 
+    /**
+     * listPage 鐨勮鏉ユ簮鏍囪锛歴hipping=鍙戣揣鍗曪紝oilOut=閿�鍞被娌瑰搧鍑哄簱
+     */
+    private static final String SOURCE_OIL_OUT = "oilOut";
+
     private final ShippingInfoMapper shippingInfoMapper;
-    private final TempFileServiceImpl tempFileService;
+
+    private final SalesLedgerArrivalMapper salesLedgerArrivalMapper;
+
     private final SalesLedgerProductMapper salesLedgerProductMapper;
+
     private final StockUtils stockUtils;
+
     private final CommonFileServiceImpl commonFileService;
+
     private final ApproveProcessServiceImpl approveProcessService;
     private final FileUtil fileUtil;
+    private final ShippingProductDetailMapper shippingProductDetailMapper;
+    private final ApprovalTemplateMapper approvalTemplateMapper;
+    private final ApprovalInstanceService approvalInstanceService;
 
     @Override
     public IPage<ShippingInfoDto> listPage(Page page, ShippingInfo req) {
         IPage<ShippingInfoDto> listPage = shippingInfoMapper.listPage(page, req);
-        listPage.getRecords().forEach(item ->{
-            item.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.IMAGE, RecordTypeEnum.ShippingInfo, item.getId()));
+        listPage.getRecords().forEach(item -> {
+            if (SOURCE_OIL_OUT.equals(item.getSource())) {
+                // 娌瑰搧鍑哄簱琛岀殑 id 鏄� stock_out_record.id锛屼笌 shipping_info.id 鍚屽煙浼氭挒鍙凤紝
+                // 鐢ㄥ畠鍘绘煡闄勪欢鍙細鎹炲嚭鍒殑鍙戣揣鍗曠殑鍥撅紝绱㈡�т笉鏌ワ紱闄勪欢鎸傚湪鍒拌揣璁板綍瀛愯涓�
+                // 娌瑰搧鍑哄簱琛屾病鏈� shipping_product_detail锛屾壒鍙锋槑缁嗗彧鑳界敱鍑哄簱璁板綍鑷韩瀛楁鏋勯��
+                item.setBatchNoList(buildOilOutBatchNoList(item));
+                return;
+            }
+            item.setStorageBlobVOs(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, item.getId()));
         });
+        assembleArrivals(listPage.getRecords());
         return listPage;
+    }
+
+    /**
+     * 鍙戣揣鍙拌处灞傜骇鍖栵細鐖惰 = 涓�娆″彂璐э紙鍙戣揣鍗� / 娌瑰搧鍑哄簱鍗曪級锛屽瓙琛� = 璇ュ嚭搴撳崟涓嬬殑鍒拌揣璁板綍銆�
+     * <p>
+     * 鍒绘剰涓嶆妸鍒拌揣璁板綍 UNION 杩涘垎椤� SQL锛氱幇鏈� UNION 鐨勬瘡涓�琛屽ぉ鐒跺氨鏄竴涓埗琛岋紝鐖惰缁村害鐨勫垎椤典笌
+     * total 宸茬粡姝g‘锛涙贩鍏ュ瓙琛屼細鎾戝ぇ鏉℃暟锛屼笖 {@code getDateilByShippingNo} 澶嶇敤鍚屼竴 listPage 鍙�
+     * 绗竴琛屾椂浼氶潤榛樺彇閿欍�傛敼鎴愪粠宸插垎椤电殑鐖惰閲屾敹闆� id锛屼竴娆℃壒閲忔煡瀛愯锛岄伩鍏� N+1銆�
+     */
+    private void assembleArrivals(List<ShippingInfoDto> records) {
+        List<Long> stockOutRecordIds = records.stream()
+                .filter(item -> SOURCE_OIL_OUT.equals(item.getSource()) && item.getStockOutRecordId() != null)
+                .map(ShippingInfoDto::getStockOutRecordId)
+                .toList();
+        if (stockOutRecordIds.isEmpty()) {
+            return;
+        }
+        Map<Long, List<SalesLedgerArrivalDto>> arrivalMap = salesLedgerArrivalMapper
+                .listByStockOutRecordIds(stockOutRecordIds).stream()
+                .collect(Collectors.groupingBy(SalesLedgerArrivalDto::getStockOutRecordId));
+        records.forEach(item -> {
+            if (!SOURCE_OIL_OUT.equals(item.getSource()) || item.getStockOutRecordId() == null) {
+                return;
+            }
+            List<SalesLedgerArrivalDto> arrivals = arrivalMap.get(item.getStockOutRecordId());
+            item.setChildren(arrivals == null ? new ArrayList<>() : new ArrayList<>(arrivals));
+        });
+    }
+
+    /**
+     * 娌瑰搧鍑哄簱琛岀殑鎵瑰彿鏄庣粏锛屼緵鍙戣揣鍙拌处璇︽儏寮规鐨勩�屾壒鍙枫�嶆槑缁嗚〃灞曠ず
+     */
+    private List<ShippingProductDetailDto> buildOilOutBatchNoList(ShippingInfoDto item) {
+        ShippingProductDetailDto detail = new ShippingProductDetailDto();
+        detail.setBatchNo(item.getOutBatchNo());
+        detail.setProductName(item.getProductName());
+        detail.setSpecificationModel(item.getSpecificationModel());
+        detail.setDeliveryQuantity(item.getTotalQuantity());
+        return Collections.singletonList(detail);
     }
 
     @Override
@@ -61,9 +138,14 @@
             throw new RuntimeException("鍙戣揣淇℃伅涓嶅瓨鍦�");
         }
         //鎵e噺搴撳瓨
-        if(!"宸插彂璐�".equals(byId.getStatus())){
-            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(byId.getSalesLedgerProductId());
-            stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
+        if (!"宸插彂璐�".equals(byId.getStatus())) {
+            List<ShippingProductDetail> shippingProductDetails = shippingProductDetailMapper.selectList(new LambdaQueryWrapper<ShippingProductDetail>().eq(ShippingProductDetail::getShippingInfoId, req.getId()));
+            if (CollectionUtils.isEmpty(shippingProductDetails)) {
+                throw new RuntimeException("鍙戣揣淇℃伅涓嶅瓨鍦�");
+            }
+            for (ShippingProductDetail shippingProductDetail : shippingProductDetails) {
+                stockUtils.substractStock(shippingProductDetail.getProductModelId(), shippingProductDetail.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(), shippingProductDetail.getBatchNo());
+            }
         }
         byId.setExpressNumber(req.getExpressNumber());
         byId.setExpressCompany(req.getExpressCompany());
@@ -72,40 +154,43 @@
         byId.setShippingDate(req.getShippingDate());
         boolean update = this.updateById(byId);
         // 淇濆瓨鏂囦欢
-        fileUtil.saveStorageAttachment(ApplicationTypeEnum.IMAGE, RecordTypeEnum.ShippingInfo, req.getId(), req.getStorageBlobDTOs());
-        return update ;
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, req.getId(), req.getStorageBlobDTOs());
+        return update;
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean delete(List<Long> ids) {
         List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                 .in(ShippingInfo::getId, ids));
-        if(CollectionUtils.isEmpty(shippingInfos)) return false;
+        if (CollectionUtils.isEmpty(shippingInfos)) return false;
+        // 鍙湁寰呭鏍哥姸鎬佹墠鑳藉垹闄�
+        boolean allPending = shippingInfos.stream().allMatch(s -> "寰呭鏍�".equals(s.getStatus()));
+        if (!allPending) throw new RuntimeException("鍙湁寰呭鏍哥姸鎬佹墠鑳藉垹闄�");
         // 鍒犻櫎闄勪欢
         commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
-        // 鎵e凡鍙戣揣搴撳瓨
-        for (ShippingInfo shippingInfo : shippingInfos) {
-            if("宸插彂璐�".equals(shippingInfo.getStatus())) {
+        // 鍒犻櫎鍙戣揣瀹℃壒
+        if (CollectionUtils.isNotEmpty(shippingInfos)) {
+            for (ShippingInfo shippingInfo : shippingInfos) {
+                List<ApproveProcess> one = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
+                        .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo()));
+                if (one != null) {
+                    List<Long> list = one.stream().map(ApproveProcess::getId).toList();
+                    approveProcessService.delByIds(list);
+                }
+                // 鎵e凡鍙戣揣搴撳瓨
                 stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
             }
         }
-        // 鍒犻櫎鍙戣揣瀹℃壒
-        if(CollectionUtils.isNotEmpty(shippingInfos)){
-            for (ShippingInfo shippingInfo : shippingInfos){
-                ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
-                        .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo()));
-                if(one != null){
-                    approveProcessService.delByIds(Collections.singletonList(one.getId()));
-                }
-            }
-        }
+        //鍒犻櫎鍙戣揣鏄庣粏
+        shippingProductDetailMapper.delete(new LambdaQueryWrapper<ShippingProductDetail>().in(ShippingProductDetail::getShippingInfoId, ids));
 
-        return this.removeBatchByIds(ids);
+        return this.removeByIds(ids);
     }
 
     @Override
-    public List<SalesLedgerProductDto> getReturnManagementDtoById(Long shippingId) {
-        return shippingInfoMapper.getReturnManagementDtoById(shippingId );
+    public List<ShippingProductVo> getReturnManagementDtoById(Long shippingId) {
+        return shippingInfoMapper.getReturnManagementDtoById(shippingId);
 
     }
 
@@ -113,4 +198,109 @@
     public List<ShippingInfo> getShippingInfoByCustomerName(String customerName) {
         return shippingInfoMapper.getShippingInfoByCustomerName(customerName);
     }
+
+    @Override
+    public boolean add(ShippingInfoDto req) {
+        this.save(req);
+        req.getBatchNoDetailList().forEach(item -> item.setShippingInfoId(req.getId()));
+        shippingProductDetailMapper.insert(req.getBatchNoDetailList());
+        for (ShippingProductDetail shippingProductDetail : req.getBatchNoDetailList()) {
+            stockUtils.substractStock(shippingProductDetail.getProductModelId(), shippingProductDetail.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(), shippingProductDetail.getBatchNo());
+        }
+        // 淇濆瓨鏂囦欢
+        fileUtil.saveStorageAttachment(ApplicationTypeEnum.IMAGE, RecordTypeEnum.SHIPPING_INFO, req.getId(), req.getStorageBlobDTOs());
+        return true;
+    }
+
+    @Override
+    public List<ShippingProductDetailDto> getDetail(Long id) {
+        return shippingProductDetailMapper.getDetail(id);
+    }
+
+    @Override
+    public ShippingApproveDto getDateilByShippingNo(String shippingNo) {
+        ShippingApproveDto shippingApproveDto = new ShippingApproveDto();
+        ShippingInfo shippingInfo = new ShippingInfo();
+        shippingInfo.setShippingNo(shippingNo);
+        shippingApproveDto.setShippingInfo(shippingInfoMapper.listPage(new Page(1, -1), shippingInfo).getRecords().get(0));
+        List<ShippingProductDetailDto> dateilByShippingNo = shippingProductDetailMapper.getDateilByShippingNo(shippingNo);
+        shippingApproveDto.setShippingProductDetailDtoList(dateilByShippingNo);
+        return shippingApproveDto;
+    }
+
+    @Override
+    public boolean addReq(ShippingInfoDto req) {
+        // 鏍¢獙璇ヤ骇鍝佹槸鍚﹀凡鏈夊緟瀹℃牳/瀹℃牳涓殑鍙戣揣璁板綍锛岄槻姝㈤噸澶嶆彁浜�
+        Long salesLedgerProductId = req.getSalesLedgerProductId();
+        if (salesLedgerProductId != null) {
+            long pendingCount = this.count(new LambdaQueryWrapper<ShippingInfo>()
+                    .eq(ShippingInfo::getSalesLedgerProductId, salesLedgerProductId)
+                    .in(ShippingInfo::getStatus, "寰呭鏍�", "瀹℃牳涓�"));
+            if (pendingCount > 0) {
+                throw new RuntimeException("璇ヤ骇鍝佸凡鏈夊緟瀹℃牳鐨勫彂璐ц褰曪紝璇峰嬁閲嶅鎻愪氦");
+            }
+        }
+
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        String sh = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SH","shipping_no",req.getCreateTime());
+        // 鍏堜繚瀛樺彂璐у崟锛屽啀鍙戣捣瀹℃壒锛涙棤瀹℃牳浜鸿嚜鍔ㄩ�氳繃鏃堕渶瑕佹寜鍙戣揣缂栧彿鍥炲啓鍙戣揣鐘舵�併��
+        req.setShippingNo(sh);
+        req.setStatus("寰呭鏍�");
+        boolean save = this.add(req);
+        // 鍙戣揣瀹℃壒
+        ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectOne(
+                new LambdaQueryWrapper<ApprovalTemplate>()
+                        .eq(ApprovalTemplate::getBusinessType, 7L)
+                        .eq(ApprovalTemplate::getDeleted, 0)
+                        .orderByDesc(ApprovalTemplate::getId)
+                        .last("LIMIT 1")
+        );
+        if (approvalTemplate == null) {
+            throw new RuntimeException("璇峰厛閰嶇疆鍙戣揣瀹℃壒妯℃澘");
+        }
+        ApprovalInstanceDto approvalInstance = new ApprovalInstanceDto();
+        approvalInstance.setTemplateId(approvalTemplate.getId());
+        approvalInstance.setTemplateName(approvalTemplate.getTemplateName());
+        approvalInstance.setBusinessId(req.getId());
+        approvalInstance.setBusinessType(7L);
+        approvalInstance.setCurrentLevel(1);
+        approvalInstance.setTitle(sh);
+        approvalInstance.setApplicantId(loginUser.getUserId());
+        approvalInstance.setApplicantName(loginUser.getNickName());
+        approvalInstance.setApplyTime(LocalDateTime.now());
+        approvalInstanceService.add(approvalInstance);
+        // 鍒涘缓瀹℃壒瀹炰緥鍚庯紝鏇存柊鍙戣揣鐘舵�佷负"瀹℃牳涓�"锛屼娇鍓嶇姝g‘鏄剧ず瀹℃壒鐘舵��
+        req.setStatus("瀹℃牳涓�");
+        this.updateById(req);
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long addShippedFromOutbound(ShippingInfoDto req) {
+        // 浠撳偍鐗╂祦鍑哄簱鍗冲彂璐э細涓嶅彂璧峰彂璐у鎵癸紝鐩存帴钀戒负宸插彂璐э紝搴撳瓨鐢� add 鍐呴儴鎵e噺
+        req.setShippingNo(OrderUtils.countTodayByCreateTime(
+                shippingInfoMapper, "SH", "shipping_no", LocalDateTime.now()));
+        req.setStatus("宸插彂璐�");
+        if (req.getShippingDate() == null) {
+            req.setShippingDate(new Date());
+        }
+        this.add(req);
+        return req.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelByOutbound(Long shippingInfoId) {
+        // <=0 蹇呴』鎸′綇锛氭补鍝佸嚭搴撶殑 record_id 鏄� 0 鑰� record_type 鍚屾牱鏄��13銆嶏紝
+        // 浼� 0 杩涙潵浼氭妸鍚岀被鍨嬬殑娌瑰搧鍑哄簱璁板綍褰撴垚鏈彂璐у崟鐨勯厤瀵瑰嚭搴撴暣鎵瑰垹鎺�
+        if (shippingInfoId == null || shippingInfoId <= 0) {
+            return;
+        }
+        // 鍥炴粴璇ュ彂璐у崟鍗犵敤鐨勫簱瀛�
+        stockUtils.deleteStockOutRecord(shippingInfoId, StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
+        shippingProductDetailMapper.delete(new LambdaQueryWrapper<ShippingProductDetail>()
+                .eq(ShippingProductDetail::getShippingInfoId, shippingInfoId));
+        this.removeById(shippingInfoId);
+    }
 }

--
Gitblit v1.9.3