package cn.iocoder.yudao.module.mes.service.em.record; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.controller.admin.em.record.vo.MesEmLastReadingRespVO; import cn.iocoder.yudao.module.mes.controller.admin.em.record.vo.MesEmRecordPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.em.record.vo.MesEmRecordRespVO; import cn.iocoder.yudao.module.mes.controller.admin.em.record.vo.MesEmRecordSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.em.meter.MesEmMeterDO; import cn.iocoder.yudao.module.mes.dal.dataobject.em.record.MesEmRecordDO; import cn.iocoder.yudao.module.mes.dal.mysql.em.record.MesEmRecordMapper; import cn.iocoder.yudao.module.mes.enums.em.MesEmEnergyTypeEnum; import cn.iocoder.yudao.module.mes.enums.em.MesEmRecordSourceEnum; import cn.iocoder.yudao.module.mes.service.em.alert.MesEmAlertService; import cn.iocoder.yudao.module.mes.service.em.meter.MesEmMeterService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** * MES 能耗抄表记录 Service 实现类 * * @author 超级管理员 */ @Service @Validated public class MesEmRecordServiceImpl implements MesEmRecordService { @Resource private MesEmRecordMapper recordMapper; @Resource private MesEmMeterService meterService; @Resource private MesEmAlertService alertService; @Override public Long createRecord(MesEmRecordSaveReqVO createReqVO) { MesEmMeterDO meter = meterService.getMeter(createReqVO.getMeterId()); if (meter == null) { throw exception(EM_METER_NOT_EXISTS); } validateRecordDateUnique(null, createReqVO.getMeterId(), createReqVO.getRecordDate()); MesEmRecordDO record = buildRecord(createReqVO, meter, null); recordMapper.insert(record); // 写入后按定额、环比、同比、跑冒滴漏规则检测预警 alertService.checkRecord(record); return record.getId(); } @Override public void updateRecord(MesEmRecordSaveReqVO updateReqVO) { validateRecordExists(updateReqVO.getId()); MesEmMeterDO meter = meterService.getMeter(updateReqVO.getMeterId()); if (meter == null) { throw exception(EM_METER_NOT_EXISTS); } validateRecordDateUnique(updateReqVO.getId(), updateReqVO.getMeterId(), updateReqVO.getRecordDate()); MesEmRecordDO record = buildRecord(updateReqVO, meter, updateReqVO.getId()); recordMapper.updateById(record); alertService.checkRecord(record); } @Override public void deleteRecord(Long id) { MesEmRecordDO record = validateRecordExists(id); recordMapper.deleteById(id); // 同步清理该记录产生的环比/同比/跑冒滴漏预警 alertService.deleteMeterAlerts(record.getMeterId(), record.getRecordDate()); } @Override public MesEmRecordDO getRecord(Long id) { return recordMapper.selectById(id); } private MesEmRecordDO validateRecordExists(Long id) { MesEmRecordDO record = recordMapper.selectById(id); if (record == null) { throw exception(EM_RECORD_NOT_EXISTS); } return record; } private void validateRecordDateUnique(Long id, Long meterId, LocalDate recordDate) { MesEmRecordDO record = recordMapper.selectByMeterIdAndDate(meterId, recordDate); if (record != null && ObjUtil.notEqual(record.getId(), id)) { throw exception(EM_RECORD_DATE_DUPLICATE); } } /** * 构建抄表记录:自动计算用量与费用,并冗余计量点/车间/产线/设备快照 */ private MesEmRecordDO buildRecord(MesEmRecordSaveReqVO reqVO, MesEmMeterDO meter, Long id) { // 期初读数:未填写时取上一条记录读数,没有历史记录则取计量点初始读数 BigDecimal prevReading = reqVO.getPrevReading(); if (prevReading == null) { MesEmRecordDO lastRecord = recordMapper.selectLastByMeterId( reqVO.getMeterId(), reqVO.getRecordDate(), id); prevReading = lastRecord != null ? lastRecord.getReading() : meter.getInitialReading(); } if (prevReading == null) { prevReading = BigDecimal.ZERO; } if (reqVO.getReading().compareTo(prevReading) < 0) { throw exception(EM_RECORD_READING_INVALID); } BigDecimal ratio = meter.getRatio() == null ? BigDecimal.ONE : meter.getRatio(); BigDecimal usage = reqVO.getReading().subtract(prevReading).multiply(ratio); BigDecimal price = reqVO.getPrice() == null ? BigDecimal.ZERO : reqVO.getPrice(); BigDecimal cost = usage.multiply(price).setScale(2, RoundingMode.HALF_UP); MesEmRecordDO record = BeanUtils.toBean(reqVO, MesEmRecordDO.class); record.setId(id); record.setMeterCode(meter.getCode()); record.setMeterName(meter.getName()); record.setEnergyType(meter.getEnergyType()); record.setUnit(meter.getUnit()); record.setRatio(ratio); record.setCoalFactor(meter.getCoalFactor()); record.setWorkshopId(meter.getWorkshopId()); record.setWorkshopName(meter.getWorkshopName()); record.setLineId(meter.getLineId()); record.setLineName(meter.getLineName()); record.setMachineryId(meter.getMachineryId()); record.setMachineryName(meter.getMachineryName()); record.setPrevReading(prevReading); record.setUsageAmount(usage); record.setPrice(price); record.setCost(cost); record.setSource(reqVO.getSource() == null ? MesEmRecordSourceEnum.MANUAL.getSource() : reqVO.getSource()); return record; } @Override public PageResult getRecordPage(MesEmRecordPageReqVO pageReqVO) { return recordMapper.selectPage(pageReqVO); } @Override public List getRecordRespVOList(List list) { if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } return BeanUtils.toBean(list, MesEmRecordRespVO.class, vo -> { vo.setEnergyTypeName(MesEmEnergyTypeEnum.getName(vo.getEnergyType())); vo.setSourceName(MesEmRecordSourceEnum.getName(vo.getSource())); }); } @Override public MesEmLastReadingRespVO getLastReading(Long meterId, LocalDate recordDate, Long excludeId) { MesEmRecordDO lastRecord = recordMapper.selectLastByMeterId(meterId, recordDate, excludeId); if (lastRecord != null) { return new MesEmLastReadingRespVO(lastRecord.getReading(), lastRecord.getRecordDate()); } MesEmMeterDO meter = meterService.getMeter(meterId); if (meter == null) { throw exception(EM_METER_NOT_EXISTS); } return new MesEmLastReadingRespVO( meter.getInitialReading() == null ? BigDecimal.ZERO : meter.getInitialReading(), null); } }