From 3c8fa3452ed9fb41ce9d3f68c81bcc4b38d19612 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期一, 31 八月 2026 20:14:41 +0800
Subject: [PATCH] fix: 统一销售和采购相关页面金额、单价、数量、总价保留6位小数
---
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 254 insertions(+), 22 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 7a70435..3c76a76 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -22,10 +22,10 @@
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.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -129,6 +129,7 @@
if (purchaseLedger.getApprovalStatus() != null) {
queryWrapper.eq(PurchaseLedger::getApprovalStatus, purchaseLedger.getApprovalStatus());
}
+ queryWrapper.orderByDesc(PurchaseLedger::getEntryDate);
return purchaseLedgerMapper.selectList(queryWrapper);
}
@@ -164,6 +165,9 @@
purchaseLedger.setApprovalStatus(1);
// 3. 鏂板鎴栨洿鏂颁富琛�
if (purchaseLedger.getId() == null) {
+ if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) {
+ purchaseLedger.setPurchaseContractNumber(generatePurchaseContractNo(purchaseLedger.getEntryDate()));
+ }
purchaseLedgerMapper.insert(purchaseLedger);
} else {
// 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
@@ -907,20 +911,37 @@
List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
salesLedgerImportDtoList.stream().map(PurchaseLedgerImportDto::getRecorderName).collect(Collectors.toList())));
for (PurchaseLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
- PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
+ PurchaseLedger existPurchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
.eq(PurchaseLedger::getPurchaseContractNumber, salesLedgerImportDto.getPurchaseContractNumber())
.last("limit 1"));
- if(purchaseLedger != null){
+ // 宸插鏍搁�氳繃鐨勯噰璐崟璺宠繃锛屼笉鍐嶉噸澶嶅鍏�
+ if (existPurchaseLedger != null && ApprovalStatusEnum.APPROVED.getCode().equals(existPurchaseLedger.getApprovalStatus())) {
continue;
}
PurchaseLedger salesLedger = new PurchaseLedger();
BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
- // 閫氳繃渚涘簲鍟嗗悕绉版煡璇D
- salesLedger.setSupplierId(customers.stream()
- .filter(customer -> customer.getSupplierName().equals(salesLedger.getSupplierName()))
- .findFirst()
- .map(SupplierManage::getId)
- .orElse(null));
+ // 寰呭鏍哥姸鎬佺殑閲囪喘鍗曪細鍒犻櫎璇ュ崟涓嬬殑浜у搧璇︽儏鍜屽鎵瑰疄渚嬶紝閲嶆柊褰曞叆璇︽儏
+ if (existPurchaseLedger != null) {
+ salesLedgerProductMapper.delete(new LambdaQueryWrapper<SalesLedgerProduct>()
+ .eq(SalesLedgerProduct::getSalesLedgerId, existPurchaseLedger.getId())
+ .eq(SalesLedgerProduct::getType, 2));
+ // 娓呯悊璇ュ崟涓嬬殑璐ㄦ璁板綍鍙婅川妫�鍙傛暟
+ deleteQualityInspectByPurchaseLedger(existPurchaseLedger.getId());
+ ApprovalInstance existApprovalInstance = approvalInstanceService.getOne(
+ Wrappers.<ApprovalInstance>lambdaQuery()
+ .eq(ApprovalInstance::getBusinessId, existPurchaseLedger.getId())
+ .eq(ApprovalInstance::getBusinessType, 5L)
+ .eq(ApprovalInstance::getDeleted, 0)
+ .orderByDesc(ApprovalInstance::getId)
+ .last("limit 1"));
+ if (existApprovalInstance != null) {
+ approvalInstanceService.delete(Collections.singletonList(existApprovalInstance.getId()));
+ }
+ salesLedger.setId(existPurchaseLedger.getId());
+ salesLedger.setApprovalStatus(ApprovalStatusEnum.PENDING.getCode());
+ }
+ // 閫氳繃渚涘簲鍟嗗悕绉版煡璇D锛屼笉瀛樺湪鍒欒嚜鍔ㄦ柊澧�
+ salesLedger.setSupplierId(findOrCreateSupplier(salesLedger.getSupplierName(), customers));
Long aLong = sysUsers.stream()
.filter(sysUser -> sysUser.getNickName().equals(salesLedger.getRecorderName()))
.findFirst()
@@ -960,7 +981,12 @@
String collect = ids.stream().map(Object::toString).collect(Collectors.joining(","));
salesLedger.setApproveUserIds(collect);
}
- purchaseLedgerMapper.insert(salesLedger);
+ if (salesLedger.getId() == null) {
+ purchaseLedgerMapper.insert(salesLedger);
+ } else {
+ // 寰呭鏍哥姸鎬侀噸鏂板綍鍏ユ椂锛屾洿鏂颁富琛�
+ purchaseLedgerMapper.updateById(salesLedger);
+ }
for (PurchaseLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) {
SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct();
@@ -968,22 +994,25 @@
salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
salesLedgerProduct.setType(2);
// 璁$畻涓嶅惈绋庢�讳环
- salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
- list.stream()
- .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel()))
- .findFirst()
- .ifPresent(map -> {
- salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
- salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
- });
+ salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 6, RoundingMode.HALF_UP));
+ // 浜у搧澶х被/瑙勬牸鍨嬪彿涓嶅瓨鍦ㄦ椂鑷姩鍒涘缓
+ String productName = salesLedgerProduct.getProductCategory();
+ if (StringUtils.isNotBlank(productName)) {
+ // 瑙勬牸鍨嬪彿涓虹┖鏃剁敤浜у搧澶х被浣滀负瑙勬牸鍨嬪彿
+ String model = StringUtils.isNotBlank(salesLedgerProduct.getSpecificationModel())
+ ? salesLedgerProduct.getSpecificationModel()
+ : productName;
+ salesLedgerProduct.setSpecificationModel(model);
+ Long productId = findOrCreateProduct(productName, list);
+ Long modelId = findOrCreateProductModel(productId, productName, model,
+ salesLedgerProduct.getUnit(), list);
+ salesLedgerProduct.setProductId(productId);
+ salesLedgerProduct.setProductModelId(modelId);
+ }
salesLedgerProduct.setRegister(loginUser.getNickName());
salesLedgerProduct.setRegisterDate(LocalDateTime.now());
salesLedgerProduct.setApproveStatus(0);
- // 鏄惁璐ㄦ鍒ゆ柇
salesLedgerProduct.setIsChecked(salesLedgerProductImportDto.getIsChecked() == 1);
- if(salesLedgerProductImportDto.getIsChecked() == 1){
- addQualityInspect(salesLedger, salesLedgerProduct);
- }
salesLedgerProductMapper.insert(salesLedgerProduct);
}
// 閲囪喘瀹℃牳
@@ -995,6 +1024,130 @@
e.printStackTrace();
}
return AjaxResult.success("瀵煎叆澶辫触");
+ }
+
+ /**
+ * 鏌ユ壘鎴栨柊澧炰緵搴斿晢锛歴upplier_manage 琛ㄦ寜 supplier_name 鍖归厤锛屼笉瀛樺湪鍒欐柊澧烇紝缂哄け淇℃伅榛樿鍐�"/"
+ */
+ private Long findOrCreateSupplier(String supplierName, List<SupplierManage> supplierList) {
+ if (StringUtils.isBlank(supplierName)) {
+ return null;
+ }
+ // 鍐呭瓨鍒楄〃涓煡鎵撅紙鏈瀵煎叆宸叉柊澧炵殑涔熷寘鍚湪鍐咃級
+ for (SupplierManage supplier : supplierList) {
+ if (supplierName.equals(supplier.getSupplierName())) {
+ return supplier.getId();
+ }
+ }
+ // 鏁版嵁搴撴煡鎵�
+ SupplierManage existSupplier = supplierManageMapper.selectOne(new LambdaQueryWrapper<SupplierManage>()
+ .eq(SupplierManage::getSupplierName, supplierName)
+ .last("limit 1"));
+ if (existSupplier != null) {
+ supplierList.add(existSupplier);
+ return existSupplier.getId();
+ }
+ // 鏂板渚涘簲鍟嗭紝缂哄け淇℃伅锛堢◣鍙枫�佸湴鍧�銆佺數璇濈瓑锛夐粯璁ゅ啓"/"
+ SupplierManage newSupplier = new SupplierManage();
+ newSupplier.setSupplierName(supplierName);
+ newSupplier.setTaxpayerIdentificationNum("/");
+ newSupplier.setCompanyAddress("/");
+ newSupplier.setSupplierType("/");
+ newSupplier.setCompanyPhone("/");
+ newSupplier.setBankAccountName("/");
+ newSupplier.setBankAccountNum("/");
+ newSupplier.setContactUserName("/");
+ newSupplier.setContactUserPhone("/");
+ supplierManageMapper.insert(newSupplier);
+ supplierList.add(newSupplier);
+ return newSupplier.getId();
+ }
+
+ /**
+ * 鏌ユ壘鎴栨柊澧炰骇鍝佸ぇ绫伙細product 琛ㄦ寜 product_name 鍖归厤锛屼笉瀛樺湪鍒欐柊澧烇紝榛樿鐖禝D涓�278
+ */
+ private Long findOrCreateProduct(String productName, List<Map<String, Object>> productAndModelList) {
+ // 鍐呭瓨鍒楄〃涓煡鎵撅紙鏈瀵煎叆宸叉柊澧炵殑涔熷寘鍚湪鍐咃級
+ for (Map<String, Object> map : productAndModelList) {
+ if (map.get("productName") != null && productName.equals(map.get("productName"))) {
+ return Long.valueOf(map.get("id").toString());
+ }
+ }
+ // 鏁版嵁搴撴煡鎵撅紙宸插瓨鍦ㄤ絾鏆傛棤瑙勬牸鍨嬪彿鐨勪骇鍝佷笉鍦ㄥ唴瀛樺垪琛ㄤ腑锛�
+ Product existProduct = productMapper.selectOne(new LambdaQueryWrapper<Product>()
+ .eq(Product::getProductName, productName)
+ .last("limit 1"));
+ if (existProduct != null) {
+ return existProduct.getId();
+ }
+ // 鏂板浜у搧澶х被锛岄粯璁ょ埗ID涓�278
+ Product product = new Product();
+ product.setProductName(productName);
+ product.setParentId(278L);
+ productMapper.insert(product);
+ return product.getId();
+ }
+
+ /**
+ * 鏌ユ壘鎴栨柊澧炰骇鍝佽鏍煎瀷鍙凤細product_model 鎸� 浜у搧ID+瑙勬牸鍨嬪彿 鍖归厤锛屼笉瀛樺湪鍒欐柊澧炪��
+ * 浜у搧缂栫爜 = 瑙勬牸鍨嬪彿 + "_" + 涓変綅娴佹按鍙凤紱瑙勬牸鍨嬪彿涓虹┖鏃剁敤浜у搧澶х被浣滀负瑙勬牸鍨嬪彿銆�
+ */
+ private Long findOrCreateProductModel(Long productId, String productName, String model, String unit,
+ List<Map<String, Object>> productAndModelList) {
+ // 鍐呭瓨鍒楄〃涓煡鎵�
+ for (Map<String, Object> map : productAndModelList) {
+ if (map.get("id") != null && Long.valueOf(map.get("id").toString()).equals(productId)
+ && model.equals(map.get("model"))) {
+ return Long.valueOf(map.get("modelId").toString());
+ }
+ }
+ // 鏁版嵁搴撴煡鎵�
+ ProductModel existProductModel = productModelMapper.selectOne(new LambdaQueryWrapper<ProductModel>()
+ .eq(ProductModel::getProductId, productId)
+ .eq(ProductModel::getModel, model)
+ .last("limit 1"));
+ if (existProductModel != null) {
+ return existProductModel.getId();
+ }
+ // 鏂板瑙勬牸鍨嬪彿锛屼骇鍝佺紪鐮� = 瑙勬牸鍨嬪彿 + "_" + 涓変綅娴佹按鍙凤紙鍚屼骇鍝佷笅鑷锛�
+ long count = productModelMapper.selectCount(new LambdaQueryWrapper<ProductModel>()
+ .eq(ProductModel::getProductId, productId));
+ ProductModel productModel = new ProductModel();
+ productModel.setProductId(productId);
+ productModel.setModel(model);
+ productModel.setUnit(unit);
+ productModel.setProductCode(model + "_" + String.format("%03d", count + 1));
+ productModelMapper.insert(productModel);
+ // 璁板綍鍒板唴瀛樺垪琛紝閬垮厤鏈瀵煎叆鍐呴噸澶嶅垱寤�
+ Map<String, Object> newMap = new HashMap<>();
+ newMap.put("id", productId);
+ newMap.put("modelId", productModel.getId());
+ newMap.put("productName", productName);
+ newMap.put("model", model);
+ productAndModelList.add(newMap);
+ return productModel.getId();
+ }
+
+ /**
+ * 鍒犻櫎閲囪喘鍗曚笅鐨勮川妫�璁板綍鍙婅川妫�鍙傛暟锛堝凡鎻愪氦鐨勬楠屽崟涓嶅厑璁稿垹闄わ級
+ */
+ private void deleteQualityInspectByPurchaseLedger(Long purchaseLedgerId) {
+ LambdaQueryWrapper<QualityInspect> inspectWrapper = new LambdaQueryWrapper<>();
+ inspectWrapper.eq(QualityInspect::getPurchaseLedgerId, purchaseLedgerId);
+ List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(inspectWrapper);
+ for (QualityInspect qualityInspect : qualityInspects) {
+ if (ObjectUtils.isNotEmpty(qualityInspect.getInspectState()) && qualityInspect.getInspectState().equals(1)) {
+ throw new BaseException("宸叉彁浜ょ殑妫�楠屽崟涓嶈兘鍒犻櫎");
+ }
+ }
+ List<Long> inspectIds = qualityInspects.stream()
+ .map(QualityInspect::getId)
+ .collect(Collectors.toList());
+ if (!inspectIds.isEmpty()) {
+ qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>()
+ .in(QualityInspectParam::getInspectId, inspectIds));
+ }
+ qualityInspectMapper.delete(inspectWrapper);
}
@Override
@@ -1030,6 +1183,7 @@
ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectOne(
new LambdaQueryWrapper<ApprovalTemplate>()
.eq(ApprovalTemplate::getBusinessType, 5L)
+ .eq(ApprovalTemplate::getDeleted, 0)
.orderByDesc(ApprovalTemplate::getId)
.last("LIMIT 1")
);
@@ -1072,4 +1226,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