From dc4f084a89f735307b76a2e4222808d58e1a9043 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期六, 16 五月 2026 11:05:07 +0800
Subject: [PATCH] chore: 配置文件修改
---
src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 250 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java
new file mode 100644
index 0000000..72e5f06
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/financial/FinIntangibleAssetServiceImpl.java
@@ -0,0 +1,250 @@
+package com.ruoyi.account.service.impl.financial;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.account.bean.dto.financial.FinIntangibleAssetDto;
+import com.ruoyi.account.mapper.financial.FinIntangibleAssetMapper;
+import com.ruoyi.account.pojo.financial.FinIntangibleAsset;
+import com.ruoyi.account.service.financial.FinIntangibleAssetService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/**
+ * 鏃犲舰璧勪骇鏈嶅姟瀹炵幇銆�
+ */
+@Service
+@RequiredArgsConstructor
+public class FinIntangibleAssetServiceImpl extends ServiceImpl<FinIntangibleAssetMapper, FinIntangibleAsset> implements FinIntangibleAssetService {
+
+ private static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
+ private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+ private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+ @Override
+ public IPage<FinIntangibleAsset> pageList(Page<FinIntangibleAsset> page, FinIntangibleAssetDto queryDto) {
+ LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+ if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetCode())) {
+ wrapper.like(FinIntangibleAsset::getAssetCode, queryDto.getAssetCode());
+ }
+ if (queryDto != null && StringUtils.isNotEmpty(queryDto.getAssetName())) {
+ wrapper.like(FinIntangibleAsset::getAssetName, queryDto.getAssetName());
+ }
+ if (queryDto != null && StringUtils.isNotEmpty(queryDto.getCategory())) {
+ wrapper.eq(FinIntangibleAsset::getCategory, queryDto.getCategory());
+ }
+ if (queryDto != null && StringUtils.isNotEmpty(queryDto.getStatus())) {
+ wrapper.eq(FinIntangibleAsset::getStatus, queryDto.getStatus());
+ }
+ wrapper.orderByDesc(FinIntangibleAsset::getId);
+ return page(page, wrapper);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean add(FinIntangibleAssetDto dto) {
+ validateForSave(dto, false);
+ if (StringUtils.isEmpty(dto.getAssetCode())) {
+ dto.setAssetCode(generateAssetCode());
+ }
+ BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+ dto.setResidualRate(residualRate);
+ BigDecimal accumulatedAmortization = defaultMoney(dto.getAccumulatedAmortization());
+ dto.setAccumulatedAmortization(accumulatedAmortization);
+ dto.setNetValue(calculateNetValue(dto.getOriginalValue(), accumulatedAmortization));
+ if (StringUtils.isEmpty(dto.getStatus())) {
+ dto.setStatus("in_use");
+ }
+ return save(dto);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean update(FinIntangibleAssetDto dto) {
+ if (dto == null || dto.getId() == null) {
+ throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+ }
+ FinIntangibleAsset existed = getById(dto.getId());
+ if (existed == null) {
+ throw new ServiceException("淇敼澶辫触锛屾棤褰㈣祫浜т笉瀛樺湪");
+ }
+ if (StringUtils.isEmpty(dto.getAssetCode())) {
+ dto.setAssetCode(existed.getAssetCode());
+ }
+ if (StringUtils.isEmpty(dto.getStatus())) {
+ dto.setStatus(existed.getStatus());
+ }
+ validateForSave(dto, true);
+ BigDecimal residualRate = normalizeResidualRate(dto.getResidualRate());
+ dto.setResidualRate(residualRate);
+ if (dto.getAccumulatedAmortization() == null) {
+ dto.setAccumulatedAmortization(defaultMoney(existed.getAccumulatedAmortization()));
+ }
+ dto.setNetValue(calculateNetValue(dto.getOriginalValue(), dto.getAccumulatedAmortization()));
+ if (dto.getNetValue().compareTo(BigDecimal.ZERO) <= 0) {
+ dto.setStatus("amortized");
+ } else if ("amortized".equals(dto.getStatus())) {
+ dto.setStatus("in_use");
+ }
+ if (dto.getValidityDate() != null
+ && dto.getValidityDate().isBefore(LocalDate.now())
+ && !"amortized".equals(dto.getStatus())) {
+ dto.setStatus("expired");
+ }
+ return updateById(dto);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean deleteByIds(List<Long> ids) {
+ if (ids == null || ids.isEmpty()) {
+ throw new ServiceException("鍒犻櫎澶辫触锛岃閫夋嫨瑕佸垹闄ょ殑鏁版嵁");
+ }
+ return removeByIds(ids);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Map<String, Object> amortize(List<Long> ids) {
+ LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+ if (ids != null && !ids.isEmpty()) {
+ wrapper.in(FinIntangibleAsset::getId, ids);
+ } else {
+ wrapper.eq(FinIntangibleAsset::getStatus, "in_use");
+ }
+ List<FinIntangibleAsset> assets = list(wrapper);
+ BigDecimal totalMonthlyAmortization = ZERO;
+ int processedCount = 0;
+ for (FinIntangibleAsset asset : assets) {
+ if (!"in_use".equals(asset.getStatus())) {
+ continue;
+ }
+ BigDecimal monthlyAmortization = calculateMonthlyAmortization(
+ asset.getOriginalValue(),
+ asset.getResidualRate(),
+ asset.getAmortizationPeriod()
+ );
+ BigDecimal accumulatedAmortization = defaultMoney(asset.getAccumulatedAmortization()).add(monthlyAmortization);
+ if (accumulatedAmortization.compareTo(defaultMoney(asset.getOriginalValue())) > 0) {
+ accumulatedAmortization = defaultMoney(asset.getOriginalValue());
+ }
+ asset.setAccumulatedAmortization(roundMoney(accumulatedAmortization));
+ asset.setNetValue(calculateNetValue(asset.getOriginalValue(), asset.getAccumulatedAmortization()));
+
+ // 瑙勫垯锛氬綋鍑�鍊� <= 0 鏃讹紝鍑�鍊煎綊闆跺苟鏍囪涓哄凡鎽婇攢瀹屻��
+ if (asset.getNetValue().compareTo(BigDecimal.ZERO) <= 0) {
+ asset.setNetValue(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
+ asset.setStatus("amortized");
+ } else if (asset.getValidityDate() != null && asset.getValidityDate().isBefore(LocalDate.now())) {
+ asset.setStatus("expired");
+ }
+ updateById(asset);
+ processedCount++;
+ totalMonthlyAmortization = totalMonthlyAmortization.add(monthlyAmortization);
+ }
+ Map<String, Object> result = new HashMap<>(4);
+ result.put("processedCount", processedCount);
+ result.put("totalMonthlyAmortization", roundMoney(totalMonthlyAmortization));
+ result.put("executionTime", LocalDateTime.now());
+ return result;
+ }
+
+ /**
+ * 鎸夋枃妗h鍒欐牎楠屾棤褰㈣祫浜ф暟鎹��
+ */
+ private void validateForSave(FinIntangibleAssetDto dto, boolean isUpdate) {
+ if (dto == null) {
+ throw new ServiceException("鏃犲舰璧勪骇鏁版嵁涓嶈兘涓虹┖");
+ }
+ if (isUpdate && dto.getId() == null) {
+ throw new ServiceException("淇敼澶辫触锛岃祫浜D涓嶈兘涓虹┖");
+ }
+ if (StringUtils.isEmpty(dto.getAssetName())) {
+ throw new ServiceException("璧勪骇鍚嶇О涓嶈兘涓虹┖");
+ }
+ if (StringUtils.isEmpty(dto.getCategory())) {
+ throw new ServiceException("璧勪骇绫诲埆涓嶈兘涓虹┖");
+ }
+ if (dto.getAcquisitionDate() == null) {
+ throw new ServiceException("鍙栧緱鏃ユ湡涓嶈兘涓虹┖");
+ }
+ if (dto.getOriginalValue() == null || dto.getOriginalValue().compareTo(BigDecimal.ZERO) < 0) {
+ throw new ServiceException("璧勪骇鍘熷�间笉鑳戒负绌轰笖涓嶈兘灏忎簬0");
+ }
+ if (dto.getAmortizationPeriod() == null || dto.getAmortizationPeriod() <= 0) {
+ throw new ServiceException("鎽婇攢骞撮檺蹇呴』澶т簬0");
+ }
+ if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(BigDecimal.ZERO) < 0) {
+ throw new ServiceException("娈嬪�肩巼涓嶈兘灏忎簬0");
+ }
+ if (dto.getResidualRate() != null && dto.getResidualRate().compareTo(ONE_HUNDRED) > 0) {
+ throw new ServiceException("娈嬪�肩巼涓嶈兘澶т簬100%");
+ }
+ if (StringUtils.isNotEmpty(dto.getAssetCode())) {
+ LambdaQueryWrapper<FinIntangibleAsset> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(FinIntangibleAsset::getAssetCode, dto.getAssetCode());
+ if (isUpdate) {
+ wrapper.ne(FinIntangibleAsset::getId, dto.getId());
+ }
+ if (count(wrapper) > 0) {
+ throw new ServiceException("璧勪骇缂栧彿宸插瓨鍦紝璇峰嬁閲嶅鎻愪氦");
+ }
+ }
+ }
+
+ /**
+ * 鏃犲舰璧勪骇鎽婇攢鍏紡锛�
+ * monthlyAmortization = originalValue * (1 - residualRate/100) / (amortizationPeriod*12)
+ */
+ private BigDecimal calculateMonthlyAmortization(BigDecimal originalValue, BigDecimal residualRate, Integer amortizationPeriod) {
+ BigDecimal normalizedOriginalValue = defaultMoney(originalValue);
+ BigDecimal normalizedResidualRate = normalizeResidualRate(residualRate);
+ BigDecimal amortizableRatio = BigDecimal.ONE.subtract(normalizedResidualRate.divide(ONE_HUNDRED, 8, RoundingMode.HALF_UP));
+ BigDecimal months = BigDecimal.valueOf((long) amortizationPeriod * 12L);
+ if (months.compareTo(BigDecimal.ZERO) <= 0) {
+ throw new ServiceException("鎽婇攢骞撮檺鏃犳晥锛屾棤娉曡鎻愭憡閿�");
+ }
+ return roundMoney(normalizedOriginalValue.multiply(amortizableRatio).divide(months, 8, RoundingMode.HALF_UP));
+ }
+
+ /**
+ * 鍑�鍊� = 鍘熷�� - 绱鎽婇攢銆�
+ */
+ private BigDecimal calculateNetValue(BigDecimal originalValue, BigDecimal accumulatedAmortization) {
+ BigDecimal value = defaultMoney(originalValue).subtract(defaultMoney(accumulatedAmortization));
+ if (value.compareTo(BigDecimal.ZERO) < 0) {
+ value = BigDecimal.ZERO;
+ }
+ return roundMoney(value);
+ }
+
+ private BigDecimal normalizeResidualRate(BigDecimal residualRate) {
+ return residualRate == null ? BigDecimal.ZERO : residualRate;
+ }
+
+ private BigDecimal defaultMoney(BigDecimal value) {
+ return value == null ? ZERO : roundMoney(value);
+ }
+
+ private BigDecimal roundMoney(BigDecimal value) {
+ if (value == null) {
+ return ZERO;
+ }
+ return value.setScale(2, RoundingMode.HALF_UP);
+ }
+
+ private String generateAssetCode() {
+ return "WX" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10);
+ }
+}
--
Gitblit v1.9.3