2 天以前 684e4306a08feeae188070f264148e6765da8dcf
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
@@ -4,27 +4,35 @@
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.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
import com.ruoyi.procurementrecord.dto.ProcurementRecordOutAdd;
import com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto;
import com.ruoyi.procurementrecord.dto.ProcurementUpdateDto;
import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutAdd;
import com.ruoyi.procurementrecord.bean.dto.ProcurementRecordOutPageDto;
import com.ruoyi.procurementrecord.bean.dto.ProcurementUpdateDto;
import com.ruoyi.procurementrecord.bean.vo.BatchNoOptionVo;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementRecord;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
import com.ruoyi.procurementrecord.service.ProcurementRecordOutService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.dto.ShippingInfoDto;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingProductDetail;
import com.ruoyi.sales.service.ShippingInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -37,31 +45,97 @@
@Slf4j
public class ProcurementRecordOutServiceImpl extends ServiceImpl<ProcurementRecordOutMapper, ProcurementRecordOut> implements ProcurementRecordOutService {
    /**
     * 出库类型:销售出库。油品销售出库即发货
     */
    private static final Integer TYPE_SALE_OUT = 2;
    /**
     * 销售产品明细类型:1销售(sales_ledger_product.type,与出库 type 语义不同)
     */
    private static final Integer LEDGER_PRODUCT_TYPE_SALE = 1;
    public final ProcurementRecordOutMapper procurementRecordOutMapper;
    public final SysUserMapper sysUserMapper;
    public final ShippingInfoService shippingInfoService;
    public final SalesLedgerProductMapper salesLedgerProductMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int stockout(ProcurementRecordOutAdd procurementRecordOutAdd) {
        SysUser sysUser = sysUserMapper.selectUserById(Long.valueOf(procurementRecordOutAdd.getUserId().toString()));
        if(sysUser == null){
            throw new RuntimeException("出库人不存在");
        }
        // 查询时间范围为当天数量
        LocalDate now = LocalDate.now();
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyyMMdd");
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordOutLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordOutLambdaQueryWrapper.ge(ProcurementRecordOut::getCreateTime, now)  // 大于等于当天
                .lt(ProcurementRecordOut::getCreateTime, now.plusDays(1)); // 小于明天
        Long aLong1 = procurementRecordOutMapper.selectCount(procurementRecordOutLambdaQueryWrapper);
        // 2. 定义日期格式(必须与字符串格式完全匹配)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime localDateTime = null;
        // 3. 转换:String → LocalDate → LocalDateTime(补充0点时间)
        if(StringUtils.isNotEmpty(procurementRecordOutAdd.getTime())){
            LocalDate localDate = LocalDate.parse(procurementRecordOutAdd.getTime(), formatter);
            // 获取当前时分秒
            LocalTime localTime = LocalTime.now();
            localDateTime = localDate.atTime(localTime);}
        // 查询采购出库数量
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getProcurementRecordStorageId, procurementRecordOutAdd.getId());
        Long aLong = procurementRecordOutMapper.selectCount(procurementRecordLambdaQueryWrapper);
        ProcurementRecordOut.ProcurementRecordOutBuilder procurementRecordOut = ProcurementRecordOut.builder()
                .procurementRecordStorageId(procurementRecordOutAdd.getId())
                .code("SC" + dateFormat.format(now) + String.format("%03d", aLong1 + 1))
                .salesLedgerProductId(procurementRecordOutAdd.getSalesLedgerProductId())
                .inboundBatches(aLong.equals(0L) ? "第1批次" : "第"+ (aLong + 1) + "批次")
                .inboundNum(new BigDecimal(procurementRecordOutAdd.getQuantity()))
                .createDate(LocalDateTime.now())
                .userId(procurementRecordOutAdd.getUserId())
                .type(procurementRecordOutAdd.getType())
                .createTime(localDateTime == null ? LocalDateTime.now() : localDateTime)
                .createUser(Long.valueOf(procurementRecordOutAdd.getUserId()))
                .createBy(sysUser.getNickName())
                .tenantId(sysUser.getTenantId());
        this.save(procurementRecordOut.build());
                .updateUser(Long.valueOf(procurementRecordOutAdd.getUserId()))
                .updateTime(LocalDateTime.now())
                .productModelId(procurementRecordOutAdd.getProductModelId())
                .batchNo(procurementRecordOutAdd.getBatchNo());
        ProcurementRecordOut record = procurementRecordOut.build();
        this.save(record);
        // 油品销售出库即发货:自动生成一条已发货的发货台账并回写关联
        if (TYPE_SALE_OUT.equals(record.getType())) {
            record.setShippingInfoId(createShippingForOutbound(record));
            this.updateById(record);
        }
        return 0;
    }
    /**
     * 按出库记录生成发货台账:批次必填,库存由发货侧扣减
     */
    private Long createShippingForOutbound(ProcurementRecordOut record) {
        if (StringUtils.isBlank(record.getBatchNo())) {
            throw new RuntimeException("请选择出库批次");
        }
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(record.getSalesLedgerProductId());
        if (salesLedgerProduct == null || !LEDGER_PRODUCT_TYPE_SALE.equals(salesLedgerProduct.getType())) {
            throw new RuntimeException("销售出库未关联到有效的销售产品明细");
        }
        ShippingProductDetail detail = new ShippingProductDetail();
        detail.setProductModelId(record.getProductModelId());
        detail.setQuantity(record.getInboundNum());
        detail.setBatchNo(record.getBatchNo());
        ShippingInfoDto shippingInfoDto = new ShippingInfoDto();
        shippingInfoDto.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        shippingInfoDto.setSalesLedgerProductId(record.getSalesLedgerProductId());
        shippingInfoDto.setBatchNoDetailList(Collections.singletonList(detail));
        return shippingInfoService.addShippedFromOutbound(shippingInfoDto);
    }
    @Override
@@ -74,10 +148,17 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePro(ProcurementUpdateDto procurementDto) {
        List<ProcurementRecordOut> procurementRecordOutByIds = getProcurementRecordOutByIds(procurementDto.getIds());
        if(CollectionUtils.isEmpty(procurementRecordOutByIds)){
            throw new RuntimeException("未查询到选中的人");
        }
        // 销售出库已生成发货单,删除出库单前先冲销发货单并归还已扣库存
        for (ProcurementRecordOut record : procurementRecordOutByIds) {
            if (record.getShippingInfoId() != null) {
                shippingInfoService.cancelByOutbound(record.getShippingInfoId());
            }
        }
        procurementRecordOutMapper.deleteBatchIds(procurementRecordOutByIds.stream().map(ProcurementRecordOut::getId).collect(Collectors.toList()));
        return 0;
@@ -85,8 +166,31 @@
    @Override
    public void export(HttpServletResponse response) {
        List<ProcurementRecordOutPageDto> list =procurementRecordOutMapper.list();
        List<ProcurementRecordOutPageDto> list = procurementRecordOutMapper.list();
        ExcelUtil<ProcurementRecordOutPageDto> util = new ExcelUtil<>(ProcurementRecordOutPageDto.class);
        util.exportExcel(response, list, "出库台账");
    }
    @Override
    public IPage<ProcurementRecordOutPageDto> listPageByProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        return procurementRecordOutMapper.listPageByProduct(page, procurementDto);
    }
    @Override
    public IPage<ProcurementRecordOutPageDto> listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto) {
        return procurementRecordOutMapper.listPageByCustom(page, procurementDto);
    }
    @Override
    public IPage<ProcurementRecordOutPageDto> listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        return procurementRecordOutMapper.listPageBySemiProduct(page, procurementDto);
    }
    @Override
    public List<BatchNoOptionVo> listBatchNoByProductModelId(Long productModelId) {
        if (productModelId == null) {
            return Collections.emptyList();
        }
        return procurementRecordOutMapper.listBatchNoByProductModelId(productModelId);
    }
}