package cn.iocoder.yudao.module.finance.service.subject;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.finance.controller.admin.subject.vo.FinAccountSubjectPageReqVO;
|
import cn.iocoder.yudao.module.finance.controller.admin.subject.vo.FinAccountSubjectSaveReqVO;
|
import cn.iocoder.yudao.module.finance.dal.dataobject.subject.FinAccountSubjectDO;
|
import cn.iocoder.yudao.module.finance.dal.mysql.subject.FinAccountSubjectMapper;
|
import cn.iocoder.yudao.module.finance.dal.mysql.voucher.FinVoucherEntryMapper;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.util.Collection;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Objects;
|
import java.util.Set;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.finance.enums.ErrorCodeConstants.*;
|
|
/**
|
* 会计科目 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class FinAccountSubjectServiceImpl implements FinAccountSubjectService {
|
|
@Resource
|
private FinAccountSubjectMapper accountSubjectMapper;
|
@Resource
|
private FinVoucherEntryMapper voucherEntryMapper;
|
|
@Override
|
public Long createAccountSubject(FinAccountSubjectSaveReqVO createReqVO) {
|
// 1. 校验科目编码唯一
|
validateSubjectCodeUnique(null, createReqVO.getSubjectCode());
|
// 2. 校验上级科目
|
validateParent(createReqVO.getParentId(), null);
|
// 3. 插入
|
FinAccountSubjectDO subject = BeanUtils.toBean(createReqVO, FinAccountSubjectDO.class);
|
accountSubjectMapper.insert(subject);
|
return subject.getId();
|
}
|
|
@Override
|
public void updateAccountSubject(FinAccountSubjectSaveReqVO updateReqVO) {
|
// 1. 校验存在
|
validateAccountSubjectExists(updateReqVO.getId());
|
// 2. 校验科目编码唯一
|
validateSubjectCodeUnique(updateReqVO.getId(), updateReqVO.getSubjectCode());
|
// 3. 校验上级科目(不能选自己,也不能选自己的下级)
|
validateParent(updateReqVO.getParentId(), updateReqVO.getId());
|
// 4. 更新
|
accountSubjectMapper.updateById(BeanUtils.toBean(updateReqVO, FinAccountSubjectDO.class));
|
}
|
|
@Override
|
public void deleteAccountSubject(Long id) {
|
FinAccountSubjectDO subject = validateAccountSubjectExists(id);
|
// 1. 校验是否存在下级科目
|
List<FinAccountSubjectDO> children = accountSubjectMapper.selectListByParentId(id);
|
if (!children.isEmpty()) {
|
throw exception(ACCOUNT_SUBJECT_HAS_CHILDREN, subject.getSubjectName(), children.size());
|
}
|
// 2. 校验是否被凭证分录引用
|
Long referencedCount = voucherEntryMapper.selectCountBySubjectCodes(List.of(subject.getSubjectCode()));
|
if (referencedCount != null && referencedCount > 0) {
|
throw exception(ACCOUNT_SUBJECT_REFERENCED, subject.getSubjectName(), referencedCount);
|
}
|
// 3. 删除
|
accountSubjectMapper.deleteById(id);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteAccountSubjectList(List<Long> ids) {
|
ids.forEach(this::deleteAccountSubject);
|
}
|
|
private FinAccountSubjectDO validateAccountSubjectExists(Long id) {
|
FinAccountSubjectDO subject = accountSubjectMapper.selectById(id);
|
if (subject == null) {
|
throw exception(ACCOUNT_SUBJECT_NOT_EXISTS);
|
}
|
return subject;
|
}
|
|
private void validateSubjectCodeUnique(Long id, String subjectCode) {
|
FinAccountSubjectDO subject = accountSubjectMapper.selectBySubjectCode(subjectCode);
|
if (subject == null) {
|
return;
|
}
|
if (id == null || !Objects.equals(subject.getId(), id)) {
|
throw exception(ACCOUNT_SUBJECT_CODE_DUPLICATE, subjectCode);
|
}
|
}
|
|
/**
|
* 校验上级科目:非空时必须存在,且不能是自己或自己的下级(避免形成环)
|
*
|
* @param parentId 上级科目编号
|
* @param selfId 当前科目编号;新增时传 null
|
*/
|
private void validateParent(Long parentId, Long selfId) {
|
if (parentId == null) {
|
return;
|
}
|
if (Objects.equals(parentId, selfId)) {
|
throw exception(ACCOUNT_SUBJECT_PARENT_SELF);
|
}
|
FinAccountSubjectDO parent = accountSubjectMapper.selectById(parentId);
|
if (parent == null) {
|
throw exception(ACCOUNT_SUBJECT_PARENT_NOT_EXISTS, parentId);
|
}
|
// 自下而上回溯,若遇到自己,说明选择的上级是自己的下级
|
Set<Long> visited = new HashSet<>();
|
Long cursor = parentId;
|
while (cursor != null && visited.add(cursor)) {
|
if (Objects.equals(cursor, selfId)) {
|
throw exception(ACCOUNT_SUBJECT_PARENT_CYCLE, parent.getSubjectName());
|
}
|
FinAccountSubjectDO node = accountSubjectMapper.selectById(cursor);
|
cursor = node == null ? null : node.getParentId();
|
}
|
}
|
|
@Override
|
public FinAccountSubjectDO getAccountSubject(Long id) {
|
return accountSubjectMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<FinAccountSubjectDO> getAccountSubjectPage(FinAccountSubjectPageReqVO pageReqVO) {
|
return accountSubjectMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public List<FinAccountSubjectDO> getAccountSubjectList() {
|
return accountSubjectMapper.selectListAll();
|
}
|
|
@Override
|
public FinAccountSubjectDO getAccountSubjectByCode(String subjectCode) {
|
return accountSubjectMapper.selectBySubjectCode(subjectCode);
|
}
|
|
@Override
|
public List<FinAccountSubjectDO> getAccountSubjectListByCodes(Collection<String> subjectCodes) {
|
return accountSubjectMapper.selectListBySubjectCodes(subjectCodes);
|
}
|
|
}
|