package com.ruoyi.business.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.basic.entity.CoalInfo;
|
import com.ruoyi.basic.mapper.CoalInfoMapper;
|
import com.ruoyi.business.dto.ProductionMasterDto;
|
import com.ruoyi.business.entity.*;
|
import com.ruoyi.business.mapper.*;
|
import com.ruoyi.business.service.ProductionMasterService;
|
import com.ruoyi.common.exception.base.BaseException;
|
import com.ruoyi.common.utils.bean.BeanUtils;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 生产主表 服务实现类
|
* </p>
|
*
|
* @author ruoyi
|
* @since 2025-06-13
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class ProductionMasterServiceImpl extends ServiceImpl<ProductionMasterMapper, ProductionMaster> implements ProductionMasterService {
|
|
private final ProductionMasterMapper productionMasterMapper;
|
|
private final ProductionInventoryMapper productionInventoryMapper;
|
|
private final ProductionMapper productionMapper;
|
|
private final OfficialInventoryMapper officialInventoryMapper;
|
|
private final CoalInfoMapper coalInfoMapper;
|
|
private final PendingInventoryMapper pendingInventoryMapper;
|
|
@Override
|
public IPage<ProductionMasterDto> selectPMList(Page page, ProductionMasterDto productionMasterDto) {
|
// 1. 构建主表查询条件
|
LambdaQueryWrapper<ProductionMaster> masterQueryWrapper = new LambdaQueryWrapper<>();
|
|
// 2. 执行主表分页查询
|
IPage<ProductionMaster> entityPage = productionMasterMapper.selectPage(page, masterQueryWrapper);
|
|
// 3. 提取主表ID列表用于批量查询子表数据
|
List<Long> masterIds = entityPage.getRecords().stream()
|
.map(ProductionMaster::getId)
|
.collect(Collectors.toList());
|
|
// 4. 批量查询关联数据(避免N+1问题)
|
Map<Long, List<Production>> productionMap = queryProductionByMasterIds(masterIds);
|
Map<Long, List<ProductionInventory>> inventoryMap = queryInventoryByMasterIds(masterIds);
|
|
// 5. 转换数据并组装结果
|
List<ProductionMasterDto> dtoList = entityPage.getRecords().stream()
|
.map(record -> {
|
ProductionMasterDto dto = new ProductionMasterDto();
|
BeanUtils.copyProperties(record, dto);
|
dto.setProductionList(productionMap.getOrDefault(record.getId(), Collections.emptyList()));
|
dto.setProductionInventoryList(inventoryMap.getOrDefault(record.getId(), Collections.emptyList()));
|
return dto;
|
})
|
.collect(Collectors.toList());
|
|
// 6. 构建返回结果
|
IPage<ProductionMasterDto> dtoPage = new Page<>();
|
BeanUtils.copyProperties(entityPage, dtoPage, "records");
|
dtoPage.setRecords(dtoList);
|
|
return dtoPage;
|
}
|
|
/**
|
* 批量查询Production数据
|
*/
|
private Map<Long, List<Production>> queryProductionByMasterIds(List<Long> masterIds) {
|
if (masterIds.isEmpty()) {
|
return Collections.emptyMap();
|
}
|
|
LambdaQueryWrapper<Production> queryWrapper = new LambdaQueryWrapper<>();
|
queryWrapper.in(Production::getProductionMasterId, masterIds);
|
List<Production> productions = productionMapper.selectList(queryWrapper);
|
|
return productions.stream()
|
.collect(Collectors.groupingBy(Production::getProductionMasterId));
|
}
|
|
/**
|
* 批量查询ProductionInventory数据
|
*/
|
private Map<Long, List<ProductionInventory>> queryInventoryByMasterIds(List<Long> masterIds) {
|
if (masterIds.isEmpty()) {
|
return Collections.emptyMap();
|
}
|
|
LambdaQueryWrapper<ProductionInventory> queryWrapper = new LambdaQueryWrapper<>();
|
queryWrapper.in(ProductionInventory::getProductionMasterId, masterIds);
|
List<ProductionInventory> inventoryList = productionInventoryMapper.selectList(queryWrapper);
|
|
return inventoryList.stream()
|
.collect(Collectors.groupingBy(ProductionInventory::getProductionMasterId));
|
}
|
|
@Override
|
@Transactional
|
public int addOrEditPM(ProductionMasterDto dto) {
|
Long masterId = dto.getId();
|
|
// 编辑场景:回滚旧库存并删除旧记录
|
if (masterId != null) {
|
rollbackOldInventory(masterId);
|
deleteChildRecords(masterId);
|
}
|
|
// 校验使用量并减少库存
|
validateAndReduceInventory(dto.getProductionInventoryList());
|
|
// 构造主表实体对象
|
ProductionMaster master = buildProductionMaster(dto);
|
|
// 插入或更新主表
|
if (masterId == null) {
|
productionMasterMapper.insert(master);
|
masterId = master.getId();
|
} else {
|
master.setId(masterId);
|
productionMasterMapper.updateById(master);
|
}
|
|
// 批量插入生产记录与库存记录
|
batchInsertProductions(masterId, dto.getProductionList());
|
batchInsertInventories(masterId, dto.getProductionInventoryList());
|
|
// 插入待入库数据
|
insertPendingInventory(dto.getProductionList());
|
|
return 1;
|
}
|
|
/**
|
* 回滚旧的库存数据(将库存数量还原)
|
*/
|
private void rollbackOldInventory(Long masterId) {
|
List<ProductionInventory> oldInventories = productionInventoryMapper.selectList(
|
new LambdaQueryWrapper<ProductionInventory>().eq(ProductionInventory::getProductionMasterId, masterId));
|
|
for (ProductionInventory oldInv : oldInventories) {
|
OfficialInventory inv = officialInventoryMapper.selectById(oldInv.getOfficialId());
|
if (inv != null) {
|
inv.setInventoryQuantity(inv.getInventoryQuantity().add(new BigDecimal(oldInv.getUsedQuantity())));
|
officialInventoryMapper.updateById(inv);
|
}
|
}
|
}
|
|
/**
|
* 删除旧的子表数据及待入库数据
|
*/
|
private void deleteChildRecords(Long masterId) {
|
productionMapper.delete(new LambdaQueryWrapper<Production>().eq(Production::getProductionMasterId, masterId));
|
productionInventoryMapper.delete(new LambdaQueryWrapper<ProductionInventory>().eq(ProductionInventory::getProductionMasterId, masterId));
|
pendingInventoryMapper.delete(new LambdaQueryWrapper<PendingInventory>().eq(PendingInventory::getMasterId, masterId));
|
}
|
|
/**
|
* 校验每条使用量是否足够,并减少正式库存数量
|
*/
|
private void validateAndReduceInventory(List<ProductionInventory> inventoryList) {
|
for (ProductionInventory inv : inventoryList) {
|
OfficialInventory official = officialInventoryMapper.selectById(inv.getOfficialId());
|
BigDecimal used = new BigDecimal(inv.getUsedQuantity());
|
if (official.getInventoryQuantity().compareTo(used) < 0) {
|
throw new BaseException("库存不足");
|
}
|
official.setInventoryQuantity(official.getInventoryQuantity().subtract(used));
|
officialInventoryMapper.updateById(official);
|
}
|
}
|
|
/**
|
* 构造主表对象并聚合字段值(如总成本、煤种等)
|
*/
|
private ProductionMaster buildProductionMaster(ProductionMasterDto dto) {
|
BigDecimal totalPurchase = BigDecimal.ZERO;
|
BigDecimal totalLabor = BigDecimal.ZERO;
|
BigDecimal totalEnergy = BigDecimal.ZERO;
|
BigDecimal totalCost = BigDecimal.ZERO;
|
BigDecimal totalDepreciation = BigDecimal.ZERO;
|
BigDecimal totalQuantity = BigDecimal.ZERO;
|
|
List<Long> coalIds = new ArrayList<>();
|
|
for (Production p : dto.getProductionList()) {
|
totalPurchase = totalPurchase.add(p.getPurchasePrice());
|
totalLabor = totalLabor.add(p.getLaborCost());
|
totalEnergy = totalEnergy.add(p.getEnergyConsumptionCost());
|
totalCost = totalCost.add(p.getTotalCost());
|
totalDepreciation = totalDepreciation.add(p.getEquipmentDepreciation());
|
totalQuantity = totalQuantity.add(p.getProductionQuantity());
|
coalIds.add(p.getCoalId());
|
}
|
|
List<CoalInfo> coalInfos = coalInfoMapper.selectList(new LambdaQueryWrapper<CoalInfo>().in(CoalInfo::getId, coalIds));
|
|
ProductionMaster master = new ProductionMaster();
|
master.setProductionQuantity(totalQuantity);
|
master.setTotalCost(totalCost);
|
master.setLaborCost(totalLabor);
|
master.setEnergyConsumptionCost(totalEnergy);
|
master.setEquipmentDepreciation(totalDepreciation);
|
master.setCoal(coalInfos.stream().map(CoalInfo::getCoal).collect(Collectors.joining(",")));
|
master.setCoalId(coalIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
|
return master;
|
}
|
|
/**
|
* 批量插入生产子表数据
|
*/
|
private void batchInsertProductions(Long masterId, List<Production> list) {
|
if (list.isEmpty()) return;
|
|
for (Production p : list) {
|
Production copy = new Production();
|
BeanUtils.copyProperties(p, copy);
|
copy.setId(null);
|
copy.setProductionMasterId(masterId);
|
productionMapper.insert(copy);
|
}
|
}
|
|
/**
|
* 批量插入库存使用子表数据
|
*/
|
private void batchInsertInventories(Long masterId, List<ProductionInventory> list) {
|
if (list.isEmpty()) return;
|
|
for (ProductionInventory p : list) {
|
p.setId(null);
|
p.setProductionMasterId(masterId);
|
productionInventoryMapper.insert(p);
|
}
|
}
|
|
/**
|
* 将加工产生的产品记录到待入库表
|
*/
|
private void insertPendingInventory(List<Production> list) {
|
for (Production p : list) {
|
PendingInventory pending = new PendingInventory();
|
pending.setCoalId(p.getCoalId());
|
pending.setInventoryQuantity(p.getProductionQuantity());
|
pending.setSupplierName("生产加工入库");
|
pending.setTotalPriceIncludingTax(p.getTotalCost());
|
pending.setPriceIncludingTax(p.getPurchasePrice());
|
pending.setPriceIncludingTax(p.getPurchasePrice());
|
pendingInventoryMapper.insert(pending);
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public int delByIds(Long[] ids) {
|
if (ids == null || ids.length == 0) {
|
return 0;
|
}
|
|
List<Long> idList = Arrays.asList(ids);
|
|
// 1. 预加载所有关联数据
|
List<ProductionInventory> allInventoryList = productionInventoryMapper.selectList(
|
new LambdaQueryWrapper<ProductionInventory>()
|
.in(ProductionInventory::getProductionMasterId, idList)
|
);
|
|
// 2. 按官方库存ID分组并计算库存调整量
|
Map<Long, BigDecimal> inventoryAdjustMap = allInventoryList.stream()
|
.collect(Collectors.groupingBy(
|
ProductionInventory::getOfficialId,
|
Collectors.reducing(
|
BigDecimal.ZERO,
|
inv -> new BigDecimal(inv.getUsedQuantity()),
|
BigDecimal::add
|
)
|
));
|
|
// 3. 批量更新官方库存 (使用SQL直接更新)
|
if (!inventoryAdjustMap.isEmpty()) {
|
inventoryAdjustMap.forEach((officialId, adjustAmount) ->
|
officialInventoryMapper.addInventoryQuantity(officialId, adjustAmount)
|
);
|
}
|
|
// 4. 批量删除关联数据
|
if (!allInventoryList.isEmpty()) {
|
List<Long> inventoryIds = allInventoryList.stream()
|
.map(ProductionInventory::getId)
|
.collect(Collectors.toList());
|
productionInventoryMapper.deleteBatchIds(inventoryIds);
|
}
|
|
// 删除生产明细
|
productionMapper.delete(
|
new LambdaQueryWrapper<Production>()
|
.in(Production::getProductionMasterId, idList)
|
);
|
|
// 5. 删除主记录
|
return productionMasterMapper.deleteBatchIds(idList);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public int deleteProductionInventory(ProductionMasterDto productionMasterDto) {
|
List<ProductionInventory> inventories = productionMasterDto.getProductionInventoryList();
|
if (CollectionUtils.isEmpty(inventories)) {
|
return 0;
|
}
|
|
// 预收集数据用于批量操作
|
Map<Long, BigDecimal> inventoryAdjustMap = new HashMap<>();
|
List<Long> productionIdsToDelete = new ArrayList<>(inventories.size());
|
|
for (ProductionInventory inventory : inventories) {
|
// 收集需要删除的生产库存ID
|
productionIdsToDelete.add(inventory.getId());
|
|
// 累计库存调整量(相同officialId的用量累加)
|
BigDecimal adjustment = new BigDecimal(inventory.getUsedQuantity());
|
inventoryAdjustMap.merge(
|
inventory.getOfficialId(),
|
adjustment,
|
BigDecimal::add
|
);
|
}
|
|
// 批量更新官方库存
|
for (Map.Entry<Long, BigDecimal> entry : inventoryAdjustMap.entrySet()) {
|
OfficialInventory official = officialInventoryMapper.selectById(entry.getKey());
|
if (official == null) {
|
throw new BaseException("官方库存不存在,ID: " + entry.getKey());
|
}
|
|
// 使用线程安全的BigDecimal操作
|
official.setInventoryQuantity(
|
Optional.ofNullable(official.getInventoryQuantity())
|
.orElse(BigDecimal.ZERO)
|
.add(entry.getValue())
|
);
|
officialInventoryMapper.updateById(official);
|
}
|
|
// 批量删除生产库存
|
if (!productionIdsToDelete.isEmpty()) {
|
productionInventoryMapper.deleteBatchIds(productionIdsToDelete);
|
}
|
|
return productionIdsToDelete.size();
|
}
|
}
|