From ee156a360b75a0e54d34a56a67930893c84d0eab Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 03 七月 2026 15:01:13 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' of http://114.132.189.42:9002/r/product-inventory-management-after into dev_New_pro
---
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java | 247 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 217 insertions(+), 30 deletions(-)
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 4f83c66..7c25815 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -6,6 +6,7 @@
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.alibaba.fastjson2.JSON;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
import com.ruoyi.approve.pojo.ApprovalInstance;
@@ -22,10 +23,11 @@
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.basic.utils.FileUtil;
-import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.enums.ApprovalStatusEnum;
import com.ruoyi.common.enums.ReviewStatusEnum;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.TypeEnums;
+import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -129,7 +131,15 @@
if (purchaseLedger.getApprovalStatus() != null) {
queryWrapper.eq(PurchaseLedger::getApprovalStatus, purchaseLedger.getApprovalStatus());
}
+ // 鍙煡璇㈠叆搴撳凡瀹℃壒閫氳繃鐨勯噰璐彴璐�
+ queryWrapper.inSql(PurchaseLedger::getId,
+ "SELECT DISTINCT record_id FROM stock_in_record WHERE approval_status = 1");
return purchaseLedgerMapper.selectList(queryWrapper);
+ }
+
+ @Override
+ public List<PurchaseLedger> selectReturnablePurchaseLedgerList(PurchaseLedger purchaseLedger) {
+ return purchaseLedgerMapper.selectReturnablePurchaseLedgerList(purchaseLedger);
}
@Override
@@ -162,21 +172,13 @@
purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId());
purchaseLedger.setApprovalStatus(1);
+ // 瀹為檯鍚堝悓閲戦濮嬬粓绛変簬鍚堝悓閲戦
+ purchaseLedger.setNetContractAmount(purchaseLedger.getContractAmount());
// 3. 鏂板鎴栨洿鏂颁富琛�
- if (purchaseLedger.getId() == null) {
- purchaseLedgerMapper.insert(purchaseLedger);
- } else {
- // 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
- ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
- .eq(ApproveProcess::getApproveType, 5)
- .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber())
- .eq(ApproveProcess::getApproveDelete, 0)
- .last("limit 1"));
- if (one != null) {
- approveProcessService.delByIds(Collections.singletonList(one.getId()));
- }
- purchaseLedgerMapper.updateById(purchaseLedger);
+ if (purchaseLedger.getId() == null && !StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) {
+ purchaseLedger.setPurchaseContractNumber(generatePurchaseContractNo(purchaseLedger.getEntryDate()));
}
+ this.saveOrUpdate(purchaseLedger);
// 4. 澶勭悊瀛愯〃鏁版嵁
List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData();
@@ -184,7 +186,17 @@
handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
}
// 6.閲囪喘瀹℃牳鏂板锛涘鎵圭鐞嗘湭閰嶇疆閲囪喘瀹℃壒浜烘椂锛屽鎵规湇鍔′細鑷姩缃负瀹℃壒閫氳繃銆�
- addApproveByPurchase(loginUser, purchaseLedger);
+ //鏌ヨ褰撳墠閲囪喘鍚堝悓鍙锋槸鍚﹀凡娣诲姞瀹℃壒锛屽鏋滄湁涓斾笉鏄┏鍥炵姸鎬侊紝鍒欎笉閲嶅娣诲姞
+ ApprovalInstance oldApprovalInstance = approvalInstanceService.getOne(Wrappers.<ApprovalInstance>lambdaQuery()
+ .eq(ApprovalInstance::getDeleted, 0)
+ .eq(ApprovalInstance::getBusinessType, TypeEnums.PURCHASE_APPROVAL.getCode())
+ .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
+ .ne(ApprovalInstance::getStatus,"REJECTED")
+ .last("limit 1")
+ );
+ if(Objects.isNull(oldApprovalInstance)){
+ addApproveByPurchase(loginUser, purchaseLedger, productList);
+ }
// 5. 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId(), purchaseLedgerDto.getStorageBlobDTOS());
return 1;
@@ -751,13 +763,30 @@
for (Long id : ids) {
PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
if(purchaseLedger != null){
- ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
+ List<ApprovalInstance> approvalInstances = approvalInstanceService.list(new LambdaQueryWrapper<ApprovalInstance>()
+ .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
+ .eq(ApprovalInstance::getBusinessType, 5L)
+ .eq(ApprovalInstance::getDeleted, 0));
+ if (CollectionUtils.isNotEmpty(approvalInstances)) {
+ approvalInstanceService.delete(
+ approvalInstances.stream()
+ .map(ApprovalInstance::getId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList())
+ );
+ }
+
+ List<ApproveProcess> approveProcesses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>()
.eq(ApproveProcess::getApproveType, 5)
.eq(ApproveProcess::getApproveDelete, 0)
- .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber())
- .last("limit 1"));
- if (one != null) {
- approveProcessService.delByIds(Collections.singletonList(one.getId()));
+ .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber()));
+ if (CollectionUtils.isNotEmpty(approveProcesses)) {
+ approveProcessService.delByIds(
+ approveProcesses.stream()
+ .map(ApproveProcess::getId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList())
+ );
}
}
}
@@ -938,6 +967,7 @@
salesLedger.setContractAmount(salesLedgerProductImportDtos.stream()
.map(PurchaseLedgerProductImportDto::getTaxInclusiveTotalPrice)
.reduce(BigDecimal.ZERO,BigDecimal::add));
+ salesLedger.setNetContractAmount(salesLedger.getContractAmount());
// 閫氳繃閿�鍞崟鍙风粦瀹氶攢鍞�
SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
.eq(SalesLedger::getSalesContractNo, salesLedger.getSalesContractNo())
@@ -987,7 +1017,12 @@
salesLedgerProductMapper.insert(salesLedgerProduct);
}
// 閲囪喘瀹℃牳
- addApproveByPurchase(loginUser,salesLedger);
+ List<SalesLedgerProduct> snapshotProducts = salesLedgerProductMapper.selectList(
+ new LambdaQueryWrapper<SalesLedgerProduct>()
+ .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId())
+ .eq(SalesLedgerProduct::getType, 2)
+ );
+ addApproveByPurchase(loginUser, salesLedger, snapshotProducts);
}
return AjaxResult.success("瀵煎叆鎴愬姛");
@@ -999,21 +1034,91 @@
@Override
public PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto) {
- // 1. 鏌ヨ涓昏〃
- PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
- .eq(PurchaseLedger::getPurchaseContractNumber, purchaseLedgerDto.getPurchaseContractNumber())
- .last("LIMIT 1"));
- if (purchaseLedger == null) {
- throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
+ PurchaseLedger purchaseLedger = null;
+ ApprovalInstance approvalSnapshotInstance = null;
+
+ // 1. 浼樺厛鎸夊綋鍓嶅鎵瑰疄渚嬫煡璇㈠揩鐓�
+ if (purchaseLedgerDto.getApprovalInstanceId() != null) {
+ approvalSnapshotInstance = approvalInstanceService.getById(purchaseLedgerDto.getApprovalInstanceId());
+ if (approvalSnapshotInstance != null && approvalSnapshotInstance.getBusinessId() != null) {
+ purchaseLedger = purchaseLedgerMapper.selectById(approvalSnapshotInstance.getBusinessId());
+ }
}
- // 2. 鏌ヨ瀛愯〃
+ // 2. 娌′紶瀹℃壒瀹炰緥ID鏃讹紝閫�鍥炲埌鎸夐噰璐悎鍚屽彿鏌ヨ
+ if (purchaseLedger == null) {
+ purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
+ .eq(PurchaseLedger::getPurchaseContractNumber, purchaseLedgerDto.getPurchaseContractNumber())
+ .last("LIMIT 1"));
+ if (purchaseLedger == null) {
+ throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
+ }
+ }
+
+ // 3. 鏌ヨ褰撳墠閲囪喘鍗曞搴旂殑瀹℃壒蹇収
+ if (approvalSnapshotInstance == null) {
+ approvalSnapshotInstance = approvalInstanceService.getOne(new LambdaQueryWrapper<ApprovalInstance>()
+ .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
+ .eq(ApprovalInstance::getBusinessType, 5L)
+ .eq(ApprovalInstance::getDeleted, 0)
+ .orderByDesc(ApprovalInstance::getId)
+ .last("LIMIT 1"));
+ }
+
+ if (approvalSnapshotInstance != null && StringUtils.hasText(approvalSnapshotInstance.getFormConfig())) {
+ try {
+ PurchaseLedgerDto snapshot = JSON.parseObject(approvalSnapshotInstance.getFormConfig(), PurchaseLedgerDto.class);
+ if (snapshot != null) {
+ snapshot.setId(purchaseLedger.getId());
+ if (snapshot.getPurchaseContractNumber() == null) {
+ snapshot.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber());
+ }
+ if (snapshot.getSupplierId() == null) {
+ snapshot.setSupplierId(purchaseLedger.getSupplierId());
+ }
+ if (snapshot.getSupplierName() == null) {
+ snapshot.setSupplierName(purchaseLedger.getSupplierName());
+ }
+ if (snapshot.getSalesContractNo() == null) {
+ snapshot.setSalesContractNo(purchaseLedger.getSalesContractNo());
+ }
+ if (snapshot.getSalesContractNoId() == null) {
+ snapshot.setSalesContractNoId(purchaseLedger.getSalesLedgerId());
+ }
+ if (snapshot.getProjectName() == null) {
+ snapshot.setProjectName(purchaseLedger.getProjectName());
+ }
+ if (snapshot.getEntryDate() == null) {
+ snapshot.setEntryDate(purchaseLedger.getEntryDate());
+ }
+ if (snapshot.getExecutionDate() == null) {
+ snapshot.setExecutionDate(purchaseLedger.getExecutionDate());
+ }
+ if (snapshot.getRemarks() == null) {
+ snapshot.setRemarks(purchaseLedger.getRemarks());
+ }
+ if (snapshot.getRecorderId() == null) {
+ snapshot.setRecorderId(purchaseLedger.getRecorderId());
+ }
+ if (snapshot.getRecorderName() == null) {
+ snapshot.setRecorderName(purchaseLedger.getRecorderName());
+ }
+ snapshot.setProductData(snapshot.getProductData() == null ? Collections.emptyList() : snapshot.getProductData());
+ snapshot.setHasChildren(CollectionUtils.isNotEmpty(snapshot.getProductData()));
+ return snapshot;
+ }
+ } catch (Exception e) {
+ log.warn("瑙f瀽閲囪喘瀹℃壒蹇収澶辫触: {}", e.getMessage());
+ }
+ }
+
+ // 4. 鏌ヨ瀛愯〃
LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
.eq(SalesLedgerProduct::getType, 2);
List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
- // 4. 杞崲 DTO
+ // 5. 杞崲 DTO
PurchaseLedgerDto resultDto = new PurchaseLedgerDto();
BeanUtils.copyProperties(purchaseLedger, resultDto);
if (!products.isEmpty()) {
@@ -1023,7 +1128,7 @@
return resultDto;
}
- public void addApproveByPurchase(LoginUser loginUser,PurchaseLedger purchaseLedger) throws Exception {
+ public void addApproveByPurchase(LoginUser loginUser, PurchaseLedger purchaseLedger, List<SalesLedgerProduct> productList) {
if (loginUser == null) {
return;
}
@@ -1048,6 +1153,10 @@
approvalInstance.setTitle(purchaseLedger.getPurchaseContractNumber()+"瀹℃壒");
approvalInstance.setApplicantName(loginUser.getNickName());
approvalInstance.setApplyTime(LocalDateTime.now());
+ PurchaseLedgerDto snapshot = new PurchaseLedgerDto();
+ BeanUtils.copyProperties(purchaseLedger, snapshot);
+ snapshot.setProductData(productList == null ? Collections.emptyList() : new ArrayList<>(productList));
+ approvalInstance.setFormConfig(JSON.toJSONString(snapshot));
approvalInstanceService.add(approvalInstance);
}
@@ -1073,4 +1182,82 @@
}
return sb.toString();
}
+
+ private static final String PURCHASE_LOCK_PREFIX = "purchase_contract_no:";
+ private static final long PURCHASE_LOCK_WAIT_TIMEOUT = 10;
+ private static final long PURCHASE_LOCK_EXPIRE_TIME = 30;
+
+ private String generatePurchaseContractNo(Date entryDate) {
+ LocalDate currentDate = entryDate != null ? DateUtils.toLocalDate(entryDate) : LocalDate.now();
+ String datePart = currentDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+ String lockKey = PURCHASE_LOCK_PREFIX + datePart;
+ String lockValue = Thread.currentThread().getId() + "-" + System.nanoTime();
+
+ try {
+ long startWaitTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startWaitTime < PURCHASE_LOCK_WAIT_TIMEOUT * 1000) {
+ Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, PURCHASE_LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
+ if (Boolean.TRUE.equals(locked)) {
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException("鑾峰彇閿佹椂琚腑鏂�", e);
+ }
+ }
+
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(lockKey))) {
+ throw new RuntimeException("鑾峰彇閲囪喘鍚堝悓缂栧彿鐢熸垚閿佸け璐ワ細瓒呮椂");
+ }
+
+ String prefix = "CG-" + datePart + "-";
+ List<PurchaseLedger> existingList = purchaseLedgerMapper.selectList(
+ new LambdaQueryWrapper<PurchaseLedger>()
+ .likeRight(PurchaseLedger::getPurchaseContractNumber, prefix)
+ .select(PurchaseLedger::getPurchaseContractNumber));
+ List<Integer> existingSequences = existingList.stream()
+ .map(PurchaseLedger::getPurchaseContractNumber)
+ .filter(Objects::nonNull)
+ .map(no -> {
+ int lastDash = no.lastIndexOf('-');
+ if (lastDash >= 0) {
+ try {
+ return Integer.parseInt(no.substring(lastDash + 1));
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+ return 0;
+ })
+ .collect(Collectors.toList());
+ int nextSequence = findFirstMissingSequence(existingSequences);
+
+ return prefix + String.format("%03d", nextSequence);
+ } finally {
+ String luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end";
+ redisTemplate.execute(
+ new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
+ Collections.singletonList(lockKey),
+ lockValue
+ );
+ }
+ }
+
+ private int findFirstMissingSequence(List<Integer> sequences) {
+ if (sequences.isEmpty()) {
+ return 1;
+ }
+ sequences.sort(Integer::compareTo);
+ int next = 1;
+ for (int seq : sequences) {
+ if (seq == next) {
+ next++;
+ } else if (seq > next) {
+ break;
+ }
+ }
+ return next;
+ }
}
--
Gitblit v1.9.3