| 2026-09-13 | yuan | ![]() |
| 2026-09-10 | gongchunyi | ![]() |
| 2026-09-10 | yuan | ![]() |
| 2026-09-09 | gongchunyi | ![]() |
| 2026-09-10 | gongchunyi | ![]() |
| 2026-09-09 | gongchunyi | ![]() |
| 2026-09-13 | yuan | ![]() |
| 2026-08-29 | yuan | ![]() |
doc/20260829_alter_sales_purchase_amount_scale_6.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,90 @@ -- éå®/éè´ç¸å ³é¡µé¢éé¢ãåä»·ãæ°éãæ»ä»·ç»ä¸ä¿ç 6 ä½å°æ° -- æ¶å页é¢ï¼é宿¥ä»·ãéå®å°è´¦ã客æ·éè´§ã客æ·å¾æ¥ãéè´å°è´¦ãä¾åºå徿¥ãéè´éè´§ãéè´æ¥è¡¨ -- ç»ä¸ä½¿ç¨ decimal(18, 6)ï¼æ´æ°ä½ä¿ç 12 ä½ï¼é¿å ç± decimal(10, 2) ç´æ¥æ¹å°æ°ä½å¯¼è´çæº¢åº -- ---------------------------- -- é宿¥ä»·ï¼sales_quotation / sales_quotation_productï¼ -- ---------------------------- ALTER TABLE `sales_quotation` MODIFY COLUMN `total_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ¥ä»·éé¢'; ALTER TABLE `sales_quotation_product` MODIFY COLUMN `quantity` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ°é', MODIFY COLUMN `unit_price` decimal(18, 6) NULL DEFAULT NULL COMMENT 'åä»·', MODIFY COLUMN `amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'éé¢'; -- ---------------------------- -- éå®å°è´¦ï¼sales_ledger / sales_ledger_productï¼ -- ---------------------------- ALTER TABLE `sales_ledger` MODIFY COLUMN `contract_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'ååéé¢ï¼äº§åå«ç¨æ»ä»·ï¼', MODIFY COLUMN `net_contract_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'å®é ååéé¢ï¼æ£åéè´§åï¼'; ALTER TABLE `sales_ledger_product` MODIFY COLUMN `quantity` decimal(18, 6) NOT NULL COMMENT 'æ°é', MODIFY COLUMN `min_stock` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æä½åºå', MODIFY COLUMN `tax_inclusive_unit_price` decimal(18, 6) NOT NULL COMMENT 'å«ç¨åä»·', MODIFY COLUMN `tax_inclusive_total_price` decimal(18, 6) NOT NULL COMMENT 'å«ç¨æ»ä»·', MODIFY COLUMN `tax_exclusive_total_price` decimal(18, 6) NOT NULL COMMENT 'ä¸å«ç¨æ»ä»·', MODIFY COLUMN `warn_num` decimal(18, 6) NULL DEFAULT NULL COMMENT 'é¢è¦æ°é'; -- å°è´¦æ¨¡æ¿ï¼ä¿å/å¥ç¨æ¨¡æ¿æ¶ä¸äº§åè¡¨ç»æä¿æä¸è´ï¼ ALTER TABLE `sales_ledger_product_template` MODIFY COLUMN `quantity` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ°é', MODIFY COLUMN `min_stock` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æä½åºå', MODIFY COLUMN `tax_inclusive_unit_price` decimal(18, 6) NULL DEFAULT NULL COMMENT 'å«ç¨åä»·', MODIFY COLUMN `tax_inclusive_total_price` decimal(18, 6) NULL DEFAULT NULL COMMENT 'å«ç¨æ»ä»·', MODIFY COLUMN `tax_exclusive_total_price` decimal(18, 6) NULL DEFAULT NULL COMMENT 'ä¸å«ç¨æ»ä»·', MODIFY COLUMN `warn_num` decimal(18, 6) NULL DEFAULT NULL COMMENT 'é¢è¦æ°é'; -- ---------------------------- -- 客æ·éè´§ï¼return_management / return_sale_product / sales_refund_amount_orderï¼ -- ---------------------------- ALTER TABLE `return_management` MODIFY COLUMN `refund_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT '鿬¾æ»é¢'; ALTER TABLE `return_sale_product` MODIFY COLUMN `num` decimal(18, 6) NOT NULL COMMENT 'éè´§äº§åæ°é', MODIFY COLUMN `price` decimal(18, 6) NULL DEFAULT NULL COMMENT 'åä»·', MODIFY COLUMN `amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'éé¢'; ALTER TABLE `sales_refund_amount_order` MODIFY COLUMN `refund_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'åºé款éé¢', MODIFY COLUMN `refunded_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT '已鿬¾éé¢', MODIFY COLUMN `not_refunded_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æªé款éé¢'; -- ---------------------------- -- 客æ·å¾æ¥ï¼å款é颿¥æºï¼account_sales_collectionãreceipt_paymentï¼ -- ---------------------------- ALTER TABLE `account_sales_collection` MODIFY COLUMN `collection_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ¶æ¬¾éé¢'; ALTER TABLE `receipt_payment` MODIFY COLUMN `receipt_payment_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT '忬¾éé¢'; -- ---------------------------- -- éè´å°è´¦ï¼purchase_ledger / purchase_ledger_templateï¼ -- ---------------------------- ALTER TABLE `purchase_ledger` MODIFY COLUMN `contract_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'ååéé¢', MODIFY COLUMN `net_contract_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'å®é ååéé¢ï¼æ£åéè´§åï¼'; ALTER TABLE `purchase_ledger_template` MODIFY COLUMN `contract_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'ååéé¢'; -- ---------------------------- -- ä¾åºå徿¥ï¼ä»æ¬¾é颿¥æºï¼account_purchase_paymentï¼ -- ---------------------------- ALTER TABLE `account_purchase_payment` MODIFY COLUMN `payment_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT '仿¬¾éé¢'; -- ---------------------------- -- éè´éè´§ï¼purchase_return_orders / purchase_return_order_productsï¼ -- ---------------------------- ALTER TABLE `purchase_return_orders` MODIFY COLUMN `total_discount_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ´åææ£é¢', MODIFY COLUMN `total_discount_rate` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æ´åææ£ç', MODIFY COLUMN `total_amount` decimal(18, 6) NULL DEFAULT NULL COMMENT 'æäº¤éé¢'; ALTER TABLE `purchase_return_order_products` MODIFY COLUMN `return_quantity` decimal(18, 6) NOT NULL DEFAULT 0.000000 COMMENT 'éè´§æ°é'; src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
@@ -97,7 +97,7 @@ if (dto.getPaymentDate() == null) { throw new ServiceException("è¯·éæ©ä»æ¬¾æ¥æ"); } if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) { if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(new BigDecimal("0.000001")) < 0) { throw new ServiceException("请è¾å ¥ä»æ¬¾éé¢"); } if (StringUtils.isEmpty(dto.getPurchaseContractNumber())) { src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
@@ -102,7 +102,7 @@ if (dto.getPaymentDate() == null) { throw new ServiceException("è¯·éæ©åæ¬¾æ¥æ"); } if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) { if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(new BigDecimal("0.000001")) < 0) { throw new ServiceException("请è¾å ¥å款éé¢"); } if (StringUtils.isEmpty(dto.getSalesContractNo())) { src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -5,13 +5,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.dto.ProductDto; import com.ruoyi.basic.dto.ProductModelDto; import com.ruoyi.basic.dto.ProductModelExportDto; import com.ruoyi.basic.dto.ProductTreeDto; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.service.IProductModelService; import com.ruoyi.basic.service.IProductService; import com.ruoyi.basic.vo.ProductModelVo; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.controller.BaseController; @@ -125,8 +123,8 @@ */ @PostMapping("/import") @Log(title = "å¯¼å ¥äº§å", businessType = BusinessType.IMPORT) public AjaxResult importProductModel(@RequestParam("file") MultipartFile file, Integer productId) { return productModelService.importProductModel(file, productId); public AjaxResult importProductModel(@RequestParam("file") MultipartFile file) { return productModelService.importProductModel(file); } /** @@ -136,7 +134,6 @@ @Operation(summary = "产åå¯¼å ¥æ¨¡æ¿") @Log(title = "产åå¯¼å ¥æ¨¡æ¿", businessType = BusinessType.EXPORT) public void importProduct(HttpServletResponse response) { ExcelUtil<ProductModelExportDto> excelUtil = new ExcelUtil<>(ProductModelExportDto.class); excelUtil.importTemplateExcel(response, "产åè§æ ¼å¯¼å ¥æ¨¡æ¿"); productService.exportImportTemplate(response); } } src/main/java/com/ruoyi/basic/dto/ProductImportRowDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ package com.ruoyi.basic.dto; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import lombok.Data; /** * äº§åæ¹éå¯¼å ¥è¡ï¼ä¸ä¸ªsheetï¼åæ/åæå/æåï¼ */ @Data public class ProductImportRowDto { @Excel(name = "产åç¶ç±»") private String productParentName; @Excel(name = "产å大类") private String productCategoryName; @Excel(name = "产ååç§°") private String productName; @Excel(name = "产åç¼ç ") private String productCode; @Excel(name = "è§æ ¼åå·") private String model; @Excel(name = "åä½") private String unit; } src/main/java/com/ruoyi/basic/service/IProductModelService.java
@@ -34,5 +34,5 @@ */ IPage<ProductModel> modelListPage(Page page , ProductDto productDto); AjaxResult importProductModel(MultipartFile file, Integer productId); AjaxResult importProductModel(MultipartFile file); } src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -8,11 +8,12 @@ import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.vo.ProductModelVo; import jakarta.servlet.http.HttpServletResponse; import java.util.List; public interface IProductService extends IService<Product> { int addOrEditProduct(ProductDto productDto); int delProductByIds(Long[] ids); @@ -20,4 +21,6 @@ List<ProductTreeDto> selectProductList(ProductDto productDto); IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel); void exportImportTemplate(HttpServletResponse response); } src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.dto.ProductDto; import com.ruoyi.basic.dto.ProductImportRowDto; import com.ruoyi.basic.dto.ProductModelDto; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; @@ -18,7 +19,6 @@ import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.sales.dto.LossProductModelDto; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.technology.mapper.TechnologyBomMapper; @@ -28,11 +28,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.concurrent.ThreadLocalRandom; /** * ã请填ååè½åç§°ãServiceä¸å¡å±å¤ç @@ -48,6 +50,8 @@ private final SalesLedgerProductMapper salesLedgerProductMapper; private final TechnologyBomMapper technologyBomMapper; private ProductModelMapper productModelMapper; private static final List<String> IMPORT_SHEET_NAMES = Arrays.asList("åææ", "åæ", "åæå", "æå"); @Override public int addOrEditProductModel(ProductModelDto productModelDto) { @@ -124,69 +128,184 @@ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult importProductModel(MultipartFile file, Integer productId) { if (productId == null) { return AjaxResult.error("请å éæ©äº§ååå¯¼å ¥è§æ ¼åå·"); public AjaxResult importProductModel(MultipartFile file) { if (file == null || file.isEmpty()) { return AjaxResult.error("è¯·éæ©è¦å¯¼å ¥çæä»¶"); } Product product = productMapper.selectById(productId); if (product == null) { return AjaxResult.error("éæ©ç产åä¸åå¨"); } Map<String, List<ProductImportRowDto>> sheetMap; try { ExcelUtil<ProductModel> productModelExcelUtil = new ExcelUtil<>(ProductModel.class); List<ProductModel> productModelList = productModelExcelUtil.importExcel(file.getInputStream()); ExcelUtil<ProductImportRowDto> excelUtil = new ExcelUtil<>(ProductImportRowDto.class); sheetMap = excelUtil.importExcelMultiSheet(IMPORT_SHEET_NAMES, file.getInputStream(), 0); } catch (Exception e) { log.error("è§£æäº§åå¯¼å ¥æä»¶å¼å¸¸", e); throw new ServiceException("产åå¯¼å ¥æä»¶è§£æå¤±è´¥"); } if (sheetMap.isEmpty()) { return AjaxResult.error("æªæ¾å° [åæ/åæå/æå] å·¥ä½è¡¨ï¼ææä»¶ä¸æ²¡ææ°æ®"); } if (CollectionUtils.isEmpty(productModelList)) { return AjaxResult.error("å¯¼å ¥æ°æ®ä¸è½ä¸ºç©º"); int successCount = 0; int skipCount = 0; Set<String> generatedCodes = new HashSet<>(); for (String sheetName : IMPORT_SHEET_NAMES) { List<ProductImportRowDto> rows = sheetMap.get(sheetName); if (CollectionUtils.isEmpty(rows)) { continue; } // è·åå½å产å䏿æçè§æ ¼åå·å List<ProductModel> existingModels = list(new LambdaQueryWrapper<ProductModel>().eq(ProductModel::getProductId, productId)); Set<String> existingModelNames = existingModels.stream().map(ProductModel::getModel).collect(Collectors.toSet()); List<ProductModel> waitToSaveList = new ArrayList<>(); int skipCount = 0; for (int i = 0; i < productModelList.size(); i++) { ProductModel item = productModelList.get(i); Long topId = findOrCreateTopProduct(sheetName); Map<String, Long> nodeCache = new HashMap<>(); Map<Long, Set<String>> codeCache = new HashMap<>(); Map<Long, Set<String>> modelCache = new HashMap<>(); for (int i = 0; i < rows.size(); i++) { ProductImportRowDto row = rows.get(i); int rowNum = i + 2; if (StringUtils.isEmpty(item.getProductCode())) { return AjaxResult.error("第 " + rowNum + " è¡å¯¼å ¥å¤±è´¥: [产åç¼ç ] ä¸è½ä¸ºç©º"); } if (StringUtils.isEmpty(item.getModel())) { return AjaxResult.error("第 " + rowNum + " è¡å¯¼å ¥å¤±è´¥: [è§æ ¼åå·] ä¸è½ä¸ºç©º"); } if (StringUtils.isEmpty(item.getUnit())) { return AjaxResult.error("第 " + rowNum + " è¡å¯¼å ¥å¤±è´¥: [åä½] ä¸è½ä¸ºç©º"); String parentName = trimToNull(row.getProductParentName()); String categoryName = trimToNull(row.getProductCategoryName()); String productName = trimToNull(row.getProductName()); if (productName == null) { throw new ServiceException("第 " + rowNum + " è¡ [产ååç§°] ä¸è½ä¸ºç©º"); } // å»é,妿已å å«è¯¥åå·,åè·³è¿ if (existingModelNames.contains(item.getModel())) { String path = String.valueOf(topId); Long currentParentId = topId; if (parentName != null) { path = path + ">" + parentName; currentParentId = ensureChildNode(nodeCache, path, currentParentId, parentName); } if (categoryName != null) { path = path + ">" + categoryName; currentParentId = ensureChildNode(nodeCache, path, currentParentId, categoryName); } path = path + ">" + productName; Long leafId = ensureChildNode(nodeCache, path, currentParentId, productName); String model = StringUtils.isEmpty(row.getModel()) ? "/" : row.getModel().trim(); // åä¸äº§åä¸åç§°ï¼äº§åèç¹ï¼+ åå·ç¸ååè·³è¿ Set<String> models = modelCache.computeIfAbsent(leafId, this::loadProductModels); if (!models.add(model)) { skipCount++; continue; } item.setProductId(product.getId()); waitToSaveList.add(item); String code = trimToNull(row.getProductCode()); if (code == null) { code = generateUniqueCode(generatedCodes); } Set<String> codes = codeCache.computeIfAbsent(leafId, this::loadProductCodes); if (!codes.add(code)) { skipCount++; continue; } existingModelNames.add(item.getModel()); ProductModel productModel = new ProductModel(); productModel.setProductId(leafId); productModel.setProductCode(code); productModel.setModel(model); productModel.setUnit(trimToNull(row.getUnit())); productModelMapper.insert(productModel); successCount++; } if (!waitToSaveList.isEmpty()) { saveBatch(waitToSaveList); } if (skipCount == 0) { return AjaxResult.success(String.format("æåå¯¼å ¥ %d æ¡æ°æ®", waitToSaveList.size())); } else { return AjaxResult.success(String.format("æåå¯¼å ¥ %d æ¡ï¼è·³è¿å·²å卿°æ® %d æ¡", waitToSaveList.size(), skipCount)); } } catch (Exception e) { log.error("å¯¼å ¥äº§åè§æ ¼å¼å¸¸", e); throw new ServiceException("å¯¼å ¥å¤±è´¥"); } String message = skipCount > 0 ? String.format("æåå¯¼å ¥ %d æ¡ï¼è·³è¿å·²åå¨ %d æ¡", successCount, skipCount) : String.format("æåå¯¼å ¥ %d æ¡", successCount); return AjaxResult.success(message); } private Long findOrCreateTopProduct(String name) { Product root = productMapper.selectOne(new LambdaQueryWrapper<Product>() .isNull(Product::getParentId) .eq(Product::getProductName, name) .last("limit 1")); if (root != null) { return root.getId(); } Product product = new Product(); product.setProductName(name); productMapper.insert(product); return product.getId(); } private Long ensureChildNode(Map<String, Long> nodeCache, String path, Long parentId, String name) { Long id = nodeCache.get(path); if (id != null) { return id; } Product existing = productMapper.selectOne(new LambdaQueryWrapper<Product>() .eq(Product::getParentId, parentId) .eq(Product::getProductName, name) .last("limit 1")); if (existing != null) { nodeCache.put(path, existing.getId()); return existing.getId(); } Product product = new Product(); product.setParentId(parentId); product.setProductName(name); productMapper.insert(product); nodeCache.put(path, product.getId()); return product.getId(); } private Set<String> loadProductCodes(Long productId) { List<ProductModel> list = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>() .eq(ProductModel::getProductId, productId)); Set<String> codes = new HashSet<>(); for (ProductModel productModel : list) { if (productModel.getProductCode() != null) { codes.add(productModel.getProductCode().trim()); } } return codes; } private Set<String> loadProductModels(Long productId) { List<ProductModel> list = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>() .eq(ProductModel::getProductId, productId)); Set<String> models = new HashSet<>(); for (ProductModel productModel : list) { if (StringUtils.isEmpty(productModel.getModel())) { models.add("/"); } else { models.add(productModel.getModel().trim()); } } return models; } private String generateUniqueCode(Set<String> generatedCodes) { for (int i = 0; i < 200; i++) { String code = randomCode(5); if (generatedCodes.contains(code)) { continue; } Long count = productModelMapper.selectCount(new LambdaQueryWrapper<ProductModel>() .eq(ProductModel::getProductCode, code)); if (count == null || count == 0) { generatedCodes.add(code); return code; } } throw new ServiceException("çæå¯ä¸äº§åç¼ç 失败ï¼è¯·éè¯"); } private static String randomCode(int length) { String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.append(chars.charAt(ThreadLocalRandom.current().nextInt(chars.length()))); } return sb.toString(); } private static String trimToNull(String value) { if (value == null) { return null; } String trimmed = value.trim(); return trimmed.isEmpty() ? null : trimmed; } } src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -15,15 +15,23 @@ import com.ruoyi.basic.vo.ProductModelVo; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Service @AllArgsConstructor @Slf4j public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService { private ProductMapper productMapper; @@ -130,16 +138,40 @@ } @Override public void exportImportTemplate(HttpServletResponse response) { String templatePath = "static/产åå¯¼å ¥æ¨¡æ¿.xlsx"; try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(templatePath)) { if (inputStream == null) { throw new FileNotFoundException("æ¨¡æ¿æä»¶ä¸åå¨ï¼" + templatePath); } response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("产åå¯¼å ¥æ¨¡æ¿.xlsx", "utf-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName); try (OutputStream outputStream = response.getOutputStream()) { byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, len); } outputStream.flush(); } } catch (IOException e) { log.error("导åºäº§åå¯¼å ¥æ¨¡æ¿å¤±è´¥", e); try { response.getWriter().write("模æ¿å¯¼åºå¤±è´¥ï¼" + e.getMessage()); } catch (IOException ex) { log.error("ååºè¾åºé误", ex); } } } @Override public int delProductByIds(Long[] ids) { // 1. å é¤å表 product_model ä¸å ³èçæ°æ® LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(ProductModel::getProductId, ids); productModelMapper.delete(queryWrapper); // 2. å é¤ä¸»è¡¨ product æ°æ® int deleteCount = productMapper.deleteBatchIds(Arrays.asList(ids)); return deleteCount; return productMapper.deleteBatchIds(Arrays.asList(ids)); } } 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); } @@ -910,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); // éè¿ä¾åºååç§°æ¥è¯¢ID 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()); } // éè¿ä¾åºååç§°æ¥è¯¢IDï¼ä¸åå¨åèªå¨æ°å¢ salesLedger.setSupplierId(findOrCreateSupplier(salesLedger.getSupplierName(), customers)); Long aLong = sysUsers.stream() .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getRecorderName())) .findFirst() @@ -963,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(); @@ -971,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); } // éè´å®¡æ ¸ @@ -1000,6 +1026,130 @@ return AjaxResult.success("å¯¼å ¥å¤±è´¥"); } /** * æ¥æ¾ææ°å¢ä¾åºåï¼supplier_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 å¹é ï¼ä¸åå¨åæ°å¢ï¼é»è®¤ç¶ID为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 public PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto) { // 1. æ¥è¯¢ä¸»è¡¨ src/main/java/com/ruoyi/sales/pojo/SalesQuotationProduct.java
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -27,11 +28,11 @@ @Schema(description = "åä½") private String unit; @Schema(description = "åä»·") private Double unitPrice; private BigDecimal unitPrice; @Schema(description = "æ°é") private Integer quantity; private BigDecimal quantity; @Schema(description = "éé¢") private Double amount; private BigDecimal amount; @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -321,7 +321,7 @@ BigDecimal remain = stockInventory.getQualitity() .subtract(stockInventory.getLockedQuantity()) .subtract(required) .divide(BigDecimal.ONE, 2, RoundingMode.CEILING); .divide(BigDecimal.ONE, 6, RoundingMode.CEILING); if (remain.compareTo(BigDecimal.ZERO) < 0) { count++; stringBuffer.append(structure.getProductName()) src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
@@ -116,9 +116,21 @@ } if (oldBom.getProductModelId() != null && !oldBom.getProductModelId().equals(technologyBom.getProductModelId())) { technologyRoutingMapper.updateProductModelByBomId(technologyBom.getProductModelId(), technologyBom.getId().longValue()); technologyBomStructureService.remove(Wrappers.<TechnologyBomStructure>lambdaQuery() .eq(TechnologyBomStructure::getBomId, technologyBom.getId().longValue())); initRootStructure(technologyBom.getId().longValue(), technologyBom.getProductModelId()); // è§æ ¼ååæ¶ä» æ´æ°æ ¹èç¹æåçè§æ ¼ï¼ä¿çä¸çº§BOMç»æ List<TechnologyBomStructure> roots = technologyBomStructureService.list(Wrappers.<TechnologyBomStructure>lambdaQuery() .eq(TechnologyBomStructure::getBomId, technologyBom.getId().longValue()) //.isNull(TechnologyBomStructure::getParentId) ); if (roots.isEmpty()) { initRootStructure(technologyBom.getId().longValue(), technologyBom.getProductModelId()); } else { ProductModel productModel = productModelService.getById(technologyBom.getProductModelId()); for (TechnologyBomStructure root : roots) { root.setProductModelId(technologyBom.getProductModelId()); root.setUnit(productModel.getUnit()); technologyBomStructureService.updateById(root); } } } if (technologyBom.getBomNo() == null) { technologyBom.setBomNo(oldBom.getBomNo()); src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -160,8 +160,8 @@ SUM(slp.quantity) AS purchaseNum, SUM(slp.tax_inclusive_total_price) AS purchaseAmount, COUNT(DISTINCT slp.sales_ledger_id) AS purchaseTimes, <!-- å¹³ååä»· = æ»éè´éé¢/æ»éè´æ°éï¼ä¿ç2ä½å°æ°ï¼é¿å é¤0 --> ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 2) AS averagePrice, <!-- å¹³ååä»· = æ»éè´éé¢/æ»éè´æ°éï¼ä¿ç6ä½å°æ°ï¼é¿å é¤0 --> ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 6) AS averagePrice, <!-- 该产åå¤§ç±»ä¸æåä¸ä¸ªå½å ¥æ¥æï¼åå°è´¦ä¸»è¡¨çentry_dateï¼ --> MAX(sl.entry_date) AS entryDate, COALESCE(NULLIF(SUM(t1.return_quantity), 0), 0) AS return_quantity, src/main/resources/static/²úÆ·µ¼ÈëÄ£°å.xlsxBinary files differ