| 2026-03-19 | buhuazhen | ![]() |
| 2026-03-19 | buhuazhen | ![]() |
| 2026-03-19 | buhuazhen | ![]() |
| 2026-03-19 | buhuazhen | ![]() |
| 2026-03-19 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
| 2026-03-18 | buhuazhen | ![]() |
pom.xml
@@ -315,13 +315,6 @@ <version>${getui-sdk.version}</version> <scope>compile</scope> </dependency> <!--hutoolå·¥å ·å --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool.version}</version> </dependency> <dependency> <groupId>cn.hutool</groupId> src/main/java/com/ruoyi/RuoYiApplication.java
@@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.scheduling.annotation.EnableScheduling; /** @@ -12,6 +13,7 @@ */ @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) @EnableScheduling @EnableAspectJAutoProxy(exposeProxy = true) public class RuoYiApplication { public static void main(String[] args) src/main/java/com/ruoyi/basic/pojo/Customer.java
@@ -115,4 +115,24 @@ @ApiModelProperty(value = "弿·è¡å·") @Excel(name = "弿·è¡å·") private String bankCode; @ApiModelProperty(value = "æ³äºº") @Excel(name = "æ³äºº") @TableField(value = "corporation") private String corporation; @ApiModelProperty(value = "ä¼ ç") @Excel(name = "ä¼ ç") @TableField(value = "fax") private String fax; @ApiModelProperty(value = "弿·è¡") @Excel(name = "弿·è¡") @TableField(value = "bank_name") private String bankName; @ApiModelProperty(value = "代ç") @Excel(name = "代ç") @TableField(value = "agent") private String agent; } src/main/java/com/ruoyi/common/enums/AuditEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,25 @@ package com.ruoyi.common.enums; import lombok.Getter; /** * @author buhuazhen * @date 2026/3/19 * @email 3038525872@qq.com */ @Getter public enum AuditEnum implements BaseEnum<Integer> { NO_AUDIT(0, "æªå®¡æ ¸"), AUDIT_SUCCESS(1, "å®¡æ ¸éè¿"), AUDIT_FAIL(2, "å®¡æ ¸å¤±è´¥"); private final Integer code; private final String value; AuditEnum(Integer code, String value) { this.code = code; this.value = value; } } src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -719,4 +719,11 @@ } return sb.toString(); } public static String padRight(String str, int length) { if (str == null) str = ""; if (str.length() >= length) return str; // ç¨ç©ºæ ¼è¡¥é½ return String.format("%-" + length + "s", str); } } src/main/java/com/ruoyi/production/controller/ProductProcessRouteItemController.java
@@ -19,6 +19,8 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -3,18 +3,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.R; import com.ruoyi.production.dto.ProductProcessRouteItemDto; import com.ruoyi.production.dto.ProductionProductMainDto; import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.production.vo.ProductAuditVo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import javax.validation.Valid; import java.util.List; @RequestMapping("productionProductMain") @@ -63,4 +61,11 @@ ExcelUtil<ProductionProductMainDto> util = new ExcelUtil<ProductionProductMainDto>(ProductionProductMainDto.class); util.exportExcel(response, list, "ç产æ¥å·¥æ°æ®"); } @PostMapping("/productAudit") public R productAudit(@RequestBody @Valid ProductAuditVo vo) { productionProductMainService.auditProductMain(vo); return R.ok(); } } src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -2,6 +2,7 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.enums.AuditEnum; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import com.ruoyi.production.pojo.ProductionProductMain; import io.swagger.annotations.ApiModelProperty; @@ -61,5 +62,6 @@ private BigDecimal workHours; private BigDecimal wages; private Long auditUserId; private String auditUserName; } src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java
@@ -51,4 +51,34 @@ @ApiModelProperty(value = "ç§æ·ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; @ApiModelProperty(value = "å®¡æ ¸ç¶æ") @TableField(value = "audit_status") private Integer auditStatus; @ApiModelProperty(value = "å®¡æ ¸äººid") @TableField(value = "audit_user_id") private Long auditUserId; @ApiModelProperty(value = "å®¡æ ¸äºº") @TableField(value = "audit_user_name") private String auditUserName; @ApiModelProperty(value = "è¢«å®¡æ ¸äººid") @TableField(value = "sure_audit_user_id") private Long sureAuditUserId; @ApiModelProperty(value = "è¢«å®¡æ ¸äºº") @TableField(value = "sure_audit_user_name") private String sureAuditUserName; @ApiModelProperty(value = "å®¡æ ¸æ¶é´") @TableField(value = "audit_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime auditTime; @ApiModelProperty(value = "å®¡æ ¸æè§") @TableField(value = "audit_opinion") private String auditOpinion; } src/main/java/com/ruoyi/production/service/ProductionProductMainService.java
@@ -5,7 +5,10 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.production.dto.ProductionProductMainDto; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.production.pojo.ProductionProductOutput; import com.ruoyi.production.vo.ProductAuditVo; import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -14,7 +17,11 @@ Boolean addProductMain(ProductionProductMainDto productionProductMainDto); void auditProductMain(@NotNull ProductAuditVo productAuditVo); Boolean removeProductMain(Long id); void nextAddProductMain(@NotNull ProductionProductOutput productionProductOutput); ArrayList<Long> listMain(List<Long> idList); } src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
@@ -18,6 +18,7 @@ import lombok.AllArgsConstructor; import org.apache.poi.ss.formula.functions.T; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -36,17 +37,13 @@ @AllArgsConstructor public class ProductProcessRouteItemServiceImpl extends ServiceImpl<ProductProcessRouteItemMapper, ProductProcessRouteItem> implements ProductProcessRouteItemService { @Autowired @Lazy private ProductionProductMainService productionProductMainService; private ProductProcessRouteItemMapper productProcessRouteItemMapper; private ProductionProductMainMapper productionProductMainMapper; private ProductionProductInputMapper productionProductInputMapper; private ProductionProductOutputMapper productionProductOutputMapper; private QualityInspectMapper qualityInspectMapper; private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper; @@ -54,9 +51,6 @@ private ProductOrderMapper productOrderMapper; private ProductProcessRouteMapper productProcessRouteMapper; private SalesLedgerProductMapper salesLedgerProductMapper; @Override src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -1,5 +1,7 @@ package com.ruoyi.production.service.impl; import cn.hutool.core.lang.Assert; import cn.hutool.extra.spring.SpringUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -11,10 +13,12 @@ import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.common.enums.AuditEnum; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.dto.ProductStructureDto; @@ -22,16 +26,21 @@ import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.production.vo.ProductAuditVo; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.quality.mapper.*; import com.ruoyi.quality.pojo.*; import com.ruoyi.quality.service.IQualityInspectService; import lombok.AllArgsConstructor; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.production.mapper.ProductionProductMainMapper; import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -39,6 +48,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @Service @@ -91,6 +101,7 @@ } @Override @Transactional(rollbackFor = Exception.class) public Boolean addProductMain(ProductionProductMainDto dto) { SysUser user = userMapper.selectUserById(dto.getUserId()); ProductionProductMain productionProductMain = new ProductionProductMain(); @@ -137,11 +148,13 @@ productionProductMain.setUserName(dto.getUserName()); productionProductMain.setProductProcessRouteItemId(dto.getProductProcessRouteItemId()); productionProductMain.setWorkOrderId(dto.getWorkOrderId()); productionProductMain.setAuditUserId(dto.getAuditUserId()); productionProductMain.setAuditUserName(dto.getAuditUserName()); productionProductMain.setStatus(0); productionProductMainMapper.insert(productionProductMain); /*æ°å¢æ¥å·¥æå ¥è¡¨*/ List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(productProcessRoute.getBomId(), productProcess.getId()); if (productStructureDtos.size() == 0) { if (productStructureDtos.isEmpty()) { //å¦æè¯¥å·¥åºæ²¡æäº§åç»æçæå ¥å,é£è¿ä¸ªæå ¥åå产åºåæ¯åä¸ä¸ª ProductStructureDto productStructureDto = new ProductStructureDto(); productStructureDto.setProductModelId(productProcessRouteItem.getProductModelId()); @@ -169,6 +182,130 @@ BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()); //åªæåæ ¼æ°é>0æè½å¢å ç¸åºæ°æ® if (productQty.compareTo(BigDecimal.ZERO) > 0) { List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId())); /*æ´æ°å·¥ååç产订å*/ ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().add(productQty)); if (ObjectUtils.isNull(productWorkOrder.getActualStartTime())) { productWorkOrder.setActualStartTime(LocalDate.now());//å®é å¼å§æ¶é´ } if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) == 0) { productWorkOrder.setActualEndTime(LocalDate.now());//å®é ç»ææ¶é´ } productWorkOrderMapper.updateById(productWorkOrder); //ç产订å ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); if (ObjectUtils.isNull(productOrder.getStartTime())) { productOrder.setStartTime(LocalDateTime.now());//å¼å§æ¶é´ } if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) { //å¦ææ¯æåä¸éå·¥åºæ¥å·¥ä¹åç产订å宿æ°é+ productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().add(productQty)); if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) == 0) { productOrder.setEndTime(LocalDateTime.now());//ç»ææ¶é´ } } productOrderMapper.updateById(productOrder); } //妿æ¥åºæ°é>0,éè¦è¿å ¥æ¥åºçåºå if (ObjectUtils.isNotEmpty(dto.getScrapQty())) { if (dto.getScrapQty().compareTo(BigDecimal.ZERO) > 0) { stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId()); } } //nextAddProductMain(productionProductOutput) // ç±äºéè¦å®¡æ ¸ï¼æä»¥éè¦æå°ä¸æ¥ return true; } @Override @Transactional(rollbackFor = Exception.class) public void auditProductMain(ProductAuditVo productAuditVo) { ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productAuditVo.getId()); // å½å审æ¹äºº è¦ä¸å½åç»å½äººä¸ºåä¸äºº Assert.isTrue(SecurityUtils.getUserId().equals(productionProductMain.getAuditUserId()), "å½åç»å½ç¨æ·ä¸æ¯å½å审æ¹äºº"); // ç¶æå¿ é¡»ä¸ºå¾ å®¡æ ¸ç¶æ if (!Objects.equals(productionProductMain.getAuditStatus(), AuditEnum.NO_AUDIT.getCode())) { throw new ServiceException("å½åç¶æå·²å®¡æ ¸,ä¸è½éå¤å®¡æ ¸"); } LambdaQueryWrapper<ProductionProductOutput> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()); queryWrapper.last("limit 1"); ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectOne(queryWrapper); ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(productionProductMain.getProductProcessRouteItemId()); switch (productAuditVo.getAuditStatus()) { case NO_AUDIT: throw new ServiceException("ä¿®æ¹å®¡æ ¸ç¶æå¤±è´¥ï¼ä¸è½ä¸ºæªå®¡æ ¸ç¶æ"); case AUDIT_SUCCESS: Assert.isTrue(productionProductOutput != null, "æ²¡ææ¾å°å¯¹åºçæ¥å·¥äº§åºè®°å½"); ((ProductionProductMainService) AopContext.currentProxy()).nextAddProductMain(productionProductOutput); break; case AUDIT_FAIL: // åå° æ´æ°å·¥ååç产订å ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); productWorkOrder.setCompleteQuantity( productWorkOrder.getCompleteQuantity() .subtract(productionProductOutput.getQuantity()) .max(BigDecimal.ZERO) ); List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId())); if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) { //å¦ææ¯æåä¸éå·¥åºæ¥å·¥ä¹åç产订å éè¦æ£é¤ productOrder.setCompleteQuantity( productOrder.getCompleteQuantity() .subtract(productionProductOutput.getQuantity()) .max(BigDecimal.ZERO) ); if (productOrder.getCompleteQuantity().compareTo(productionProductOutput.getQuantity()) > 0) { productOrder.setEndTime(null); } productOrderMapper.updateById(productOrder); } if (productWorkOrder.getCompleteQuantity().compareTo(productionProductOutput.getQuantity()) > 0) { productWorkOrder.setActualEndTime(null); } productWorkOrderMapper.updateById(productWorkOrder); break; } // ä¿®æ¹ç¶æ ProductionProductMain updateDate = new ProductionProductMain(); updateDate.setId(productionProductMain.getId()); updateDate.setAuditStatus(productAuditVo.getAuditStatus().getCode()); updateDate.setSureAuditUserId(SecurityUtils.getUserId()); updateDate.setSureAuditUserName(SecurityUtils.getUsername()); updateDate.setAuditTime(LocalDateTime.now()); updateDate.setAuditOpinion(productAuditVo.getAuditOpinion()); productionProductMainMapper.updateById(updateDate); } @Override @Transactional(rollbackFor = Exception.class) public void nextAddProductMain(@NotNull ProductionProductOutput productionProductOutput){ //åæ ¼æ°é=æ¥å·¥æ°é-æ¥åºæ°é ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productionProductOutput.getProductMainId()); BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()); ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(productionProductMain.getProductProcessRouteItemId()); ProductProcess productProcess = productProcessMapper.selectById(productProcessRouteItem.getProcessId()); //å·¥èºè·¯çº¿ä¸å½åå·¥åºå¯¹åºç产åºè§æ ¼åå· ProductModel productModel = productModelMapper.selectById(productProcessRouteItem.getProductModelId()); SysUser user = userMapper.selectUserById(SecurityUtils.getUserId()); //åªæåæ ¼æ°é>0æè½å¢å ç¸åºæ°æ® if (productQty.compareTo(BigDecimal.ZERO) > 0) { /*æ°å¢è´¨æ£*/ List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId())); if (productProcessRouteItem.getIsQuality()) { @@ -194,7 +331,7 @@ qualityInspect.setProductModelId(productModel.getId()); qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process); if (qualityTestStandard.size() > 0) { if (!qualityTestStandard.isEmpty()) { qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId()); qualityInspectMapper.updateById(qualityInspect); qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery() @@ -211,29 +348,7 @@ //ç´æ¥å ¥åº stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId()); } /*æ´æ°å·¥ååç产订å*/ ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().add(productQty)); if (ObjectUtils.isNull(productWorkOrder.getActualStartTime())) { productWorkOrder.setActualStartTime(LocalDate.now());//å®é å¼å§æ¶é´ } if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) == 0) { productWorkOrder.setActualEndTime(LocalDate.now());//å®é ç»ææ¶é´ } productWorkOrderMapper.updateById(productWorkOrder); //ç产订å ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); if (ObjectUtils.isNull(productOrder.getStartTime())) { productOrder.setStartTime(LocalDateTime.now());//å¼å§æ¶é´ } if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) { //å¦ææ¯æåä¸éå·¥åºæ¥å·¥ä¹åç产订å宿æ°é+ productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().add(productQty)); if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) == 0) { productOrder.setEndTime(LocalDateTime.now());//ç»ææ¶é´ } } productOrderMapper.updateById(productOrder); /*æ·»å çäº§æ ¸ç® åºåå·¥åºæ¯è®¡ä»¶è¿æ¯è®¡æ¶*/ BigDecimal workHours = (productProcess.getType() == 1) ? productProcess.getSalaryQuota().multiply(productQty) @@ -247,17 +362,10 @@ .workHours(workHours) .process(productProcess.getName()) .schedulingDate(LocalDate.now()) .tenantId(dto.getTenantId()) .tenantId(productionProductOutput.getTenantId()) .build(); salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting); } //妿æ¥åºæ°é>0,éè¦è¿å ¥æ¥åºçåºå if (ObjectUtils.isNotEmpty(dto.getScrapQty())) { if (dto.getScrapQty().compareTo(BigDecimal.ZERO) > 0) { stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId()); } } return true; } @Override src/main/java/com/ruoyi/production/vo/ProductAuditVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,28 @@ package com.ruoyi.production.vo; import com.ruoyi.common.enums.AuditEnum; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotNull; import java.io.Serializable; /** * @author buhuazhen * @date 2026/3/19 * @email 3038525872@qq.com */ @Data @AllArgsConstructor @NoArgsConstructor public class ProductAuditVo implements Serializable { @NotNull(message = "idä¸è½ä¸ºç©º") private Long id; @NotNull(message = "å®¡æ ¸ç¶æä¸è½ä¸ºç©º") private AuditEnum auditStatus; // å®¡æ ¸æè§ private String auditOpinion; } src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -179,6 +179,12 @@ util.exportExcel(response, salesLedgerIPage == null ? new ArrayList<>() : salesLedgerIPage.getRecords(), "导åºå¼ç¥¨ç»è®°å表"); } @Log(title = "导åºå å·¥æ¿æ½åå", businessType = BusinessType.EXPORT) @GetMapping("/exportProcessContract/{id}") public void exportProcessContract(@PathVariable Long id){ salesLedgerService.exportProcessContract(id); } /** * æ°å¢ä¿®æ¹éå®å°è´¦ */ src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -58,4 +58,6 @@ @ApiModelProperty(value = "äº¤è´§æ¥æ") private LocalDate deliveryDate; private String placeOfSinging; } src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -147,5 +147,9 @@ @TableField(exist = false) //æ¯å¦å¯ç¼è¾ private Boolean isEdit; // ç¾è®¢å°ç¹ @TableField(value = "place_of_singing") private String placeOfSinging; } src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -52,4 +52,10 @@ List<LossProductModelDto> getSalesLedgerWithProductsLoss(Long salesLedgerId); IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page); /** * 导åºå å·¥æ¿æ½åå * @param id */ void exportProcessContract(@NotNull Long id); } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -1,5 +1,10 @@ package com.ruoyi.sales.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -8,8 +13,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; import com.ruoyi.account.service.AccountIncomeService; import com.ruoyi.aftersalesservice.pojo.AfterSalesService; import com.ruoyi.basic.mapper.CustomerMapper; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; @@ -27,37 +34,42 @@ import com.ruoyi.other.mapper.TempFileMapper; import com.ruoyi.other.pojo.TempFile; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.production.service.impl.ProductionProductMainServiceImpl; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.sales.dto.*; import com.ruoyi.sales.mapper.*; import com.ruoyi.sales.pojo.*; import com.ruoyi.sales.service.ISalesLedgerProductService; import com.ruoyi.sales.service.ISalesLedgerService; import com.ruoyi.sales.vo.ExportProcessContractVo; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotNull; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -81,69 +93,28 @@ @RequiredArgsConstructor @Slf4j public class SalesLedgerServiceImpl extends ServiceImpl<SalesLedgerMapper, SalesLedger> implements ISalesLedgerService { private final AccountIncomeService accountIncomeService; private final SalesLedgerMapper salesLedgerMapper; private final CustomerMapper customerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl; private final CommonFileMapper commonFileMapper; private final TempFileMapper tempFileMapper; private final ReceiptPaymentMapper receiptPaymentMapper; private final ShippingInfoServiceImpl shippingInfoServiceImpl; private final CommonFileServiceImpl commonFileService; private final ShippingInfoMapper shippingInfoMapper; private final InvoiceLedgerMapper invoiceLedgerMapper; private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper; private final SalesLedgerWorkMapper salesLedgerWorkMapper; private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper; private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper; private final InvoiceRegistrationMapper invoiceRegistrationMapper; private final ProductOrderMapper productOrderMapper; private final ProcessRouteMapper processRouteMapper; private final ProductProcessRouteMapper productProcessRouteMapper; private final ProcessRouteItemMapper processRouteItemMapper; private final ProductProcessRouteItemMapper productProcessRouteItemMapper; private final ProductWorkOrderMapper productWorkOrderMapper; private final ProductionProductMainMapper productionProductMainMapper; private final ProductionProductOutputMapper productionProductOutputMapper; private final ProductionProductInputMapper productionProductInputMapper; private final QualityInspectMapper qualityInspectMapper; @Autowired private SysDeptMapper sysDeptMapper; @Value("${file.upload-dir}") private String uploadDir; private static final String LOCK_PREFIX = "contract_no_lock:"; private static final long LOCK_WAIT_TIMEOUT = 10; // éçå¾ è¶ æ¶æ¶é´ï¼ç§ï¼ private static final long LOCK_EXPIRE_TIME = 30; // éèªå¨è¿ææ¶é´ï¼ç§ï¼ private final AccountIncomeService accountIncomeService; private final SalesLedgerMapper salesLedgerMapper; private final CustomerMapper customerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl; private final CommonFileMapper commonFileMapper; private final TempFileMapper tempFileMapper; private final ReceiptPaymentMapper receiptPaymentMapper; private final ShippingInfoServiceImpl shippingInfoServiceImpl; private final CommonFileServiceImpl commonFileService; private final ShippingInfoMapper shippingInfoMapper; private final InvoiceLedgerMapper invoiceLedgerMapper; private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper; private final InvoiceRegistrationMapper invoiceRegistrationMapper; private final RedisTemplate<String, String> redisTemplate; @Autowired private SysDeptMapper sysDeptMapper; @Value("${file.upload-dir}") private String uploadDir; @Autowired private ProductModelMapper productModelMapper; @@ -152,16 +123,18 @@ @Autowired private ProductStructureMapper productStructureMapper; @Autowired @Lazy private ProductionProductMainService productionProductMainService; ; @Autowired private SysUserMapper sysUserMapper; @Override public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) { return salesLedgerMapper.selectSalesLedgerList(salesLedgerDto); } public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type){ public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type) { LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, relateId); productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); @@ -339,9 +312,6 @@ return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto); } @Autowired private SysUserMapper sysUserMapper; @Override @Transactional(rollbackFor = Exception.class) public AjaxResult importData(MultipartFile file) { @@ -497,35 +467,99 @@ return salesLedgerDtoIPage; } @Override public void exportProcessContract(Long id) { //å å·¥æ¿æ½åå ExportProcessContractVo exportProcessContract = new ExportProcessContractVo(); exportProcessContract.setId(id); SalesLedger salesLedger = salesLedgerMapper.selectById(id); // æ¥è¯¢å®¢æ·å ¬å¸ä¿¡æ¯ Customer customer = customerMapper.selectById(salesLedger.getCustomerId()); exportProcessContract.setCreateTime(LocalDateTimeUtil.format(Optional.ofNullable(salesLedger.getExecutionDate()).orElse(LocalDate.now()), "yyyyå¹´MMæddæ¥")); exportProcessContract.setRemark(Optional.ofNullable(salesLedger.getRemarks()).orElse("æ ")); // 夿³¨ exportProcessContract.setPlaceOfSinging(Optional.ofNullable(salesLedger.getPlaceOfSinging()).orElse("")); // å é¨ç±»ç¨äºåå¨èåç»æ private static class GroupedCustomer { private final Long customerId; private final String customerName; private BigDecimal totalAmount = BigDecimal.ZERO; // å¡«åç²æ¹ä¿¡æ¯ ExportProcessContractVo.Customer partyA = ExportProcessContractVo.Customer.getCustomer(customer); exportProcessContract.setPartyAClientName(customer.getCustomerName()); exportProcessContract.setPartyA(partyA); public GroupedCustomer(Long customerId, String customerName) { this.customerId = customerId; this.customerName = customerName; // å¡«å乿¹ä¿¡æ¯ ExportProcessContractVo.Customer partyB = new ExportProcessContractVo.Customer(); exportProcessContract.setPartyBClientName("天津é³å 彩å°è¡ä»½æéå ¬å¸"); partyB.setBankName("åè¡å¤©æ´¥æ¦æ¸ å¼ååºæ¯è¡"); partyB.setBankCode("02061601040014681"); partyB.setTaxpayerIdentificationNumber("91120000562687393p"); partyB.setAddress("å¤©æ´¥æ¦æ¸ åºå¼ååºæ³å·åè·¯29å·"); partyB.setFax("022-82126666"); partyB.setPostCode("301700"); exportProcessContract.setPartyB(partyB); // å¡«åååä¿¡æ¯ final BigDecimal[] totalAmount = {BigDecimal.ZERO}; // æ»éé¢ LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()); productWrapper.eq(SalesLedgerProduct::getType, 1); List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper); List<ExportProcessContractVo.SaleProduct> productList = products.stream().map(it -> { ExportProcessContractVo.SaleProduct saleProduct = BeanUtil.copyProperties(it, ExportProcessContractVo.SaleProduct.class); // è®¡ç®æ»ä»·æ ¼ totalAmount[0] = totalAmount[0].add(Optional.ofNullable(saleProduct.getTaxInclusiveTotalPrice()).orElse(BigDecimal.ZERO)); return saleProduct; }).collect(Collectors.toList()); // 第ä¸ä¸ªè®¾ç½® ååç¼å· if (!productList.isEmpty()) { productList.get(0).setSalesContractNo(salesLedger.getSalesContractNo()); } // æ¥çç¨ç ç论ä¸ç¨çåä¸ï¼å¦æå¤ç¨ç为空 Map<BigDecimal, Long> rateMap = productList.stream().map(product -> product.getTaxRate()).filter(Objects::nonNull) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); String taxRateStr = rateMap.size() == 1 ? rateMap.keySet().iterator().next().toString() + " %" : ""; exportProcessContract.setTaxRate(taxRateStr); exportProcessContract.setSaleProducts(productList);// ååä¿¡æ¯ // 设置大åçæ»ä»·æ ¼ exportProcessContract.setTotalAmountZh(Convert.digitToChinese(totalAmount[0].doubleValue())); exportProcessContractToWord(exportProcessContract); } @SneakyThrows private void exportProcessContractToWord(@NotNull ExportProcessContractVo exportProcessContract) { // ç¡®ä¿ saleProducts ä¸ä¸º null if (exportProcessContract.getSaleProducts() == null) { exportProcessContract.setSaleProducts(new ArrayList<>()); } public void addAmount(BigDecimal amount) { if (amount != null) { this.totalAmount = this.totalAmount.add(amount); } } // 模æ¿è¾å ¥æµ InputStream inputStream = this.getClass().getResourceAsStream("/static/contract_tmp.docx"); Assert.isTrue(inputStream != null, "模æ¿ä¸åå¨"); public Long getCustomerId() { return customerId; } // 转 Map Map<String, Object> dataMap = BeanUtil.beanToMap(exportProcessContract); public String getCustomerName() { return customerName; } // ç»å®å¾ªç¯çç¥ Configure configure = Configure.builder() .bind("saleProducts", new LoopRowTableRenderPolicy()) .build(); public BigDecimal getTotalAmount() { return totalAmount; } // æ¸²ææ¨¡æ¿ XWPFTemplate template = XWPFTemplate.compile(inputStream, configure) .render(dataMap); // template.write(FileUtil.getOutputStream("/Users/ONEX/Downloads/a.docx")); // è¾åºå°æµè§å¨ HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())) .getResponse(); String rawFileName = StrUtil.format("{}-{}åå.docx", exportProcessContract.getPartyAClientName(), exportProcessContract.getCreateTime()); String encodedFileName = URLEncoder.encode(rawFileName, StandardCharsets.UTF_8.toString()); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); template.write(response.getOutputStream()); template.close(); response.flushBuffer(); } /** @@ -646,7 +680,7 @@ // 4. å¤çåè¡¨æ°æ® List<SalesLedgerProduct> productList = salesLedgerDto.getProductData(); if (productList != null && !productList.isEmpty()) { handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class,salesLedgerDto.getType())); handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType())); updateMainContractAmount( salesLedger.getId(), productList, @@ -665,8 +699,6 @@ throw new BaseException("æä»¶è¿ç§»å¤±è´¥: " + e.getMessage()); } } // æä»¶è¿ç§»æ¹æ³ /** * å°ä¸´æ¶æä»¶è¿ç§»å°æ£å¼ç®å½ @@ -743,6 +775,7 @@ } } // æä»¶è¿ç§»æ¹æ³ @Override public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) { @@ -884,4 +917,34 @@ throw new RuntimeException("å¨ææ´æ°ä¸»è¡¨éé¢å¤±è´¥", e); } } // å é¨ç±»ç¨äºåå¨èåç»æ private static class GroupedCustomer { private final Long customerId; private final String customerName; private BigDecimal totalAmount = BigDecimal.ZERO; public GroupedCustomer(Long customerId, String customerName) { this.customerId = customerId; this.customerName = customerName; } public void addAmount(BigDecimal amount) { if (amount != null) { this.totalAmount = this.totalAmount.add(amount); } } public Long getCustomerId() { return customerId; } public String getCustomerName() { return customerName; } public BigDecimal getTotalAmount() { return totalAmount; } } } src/main/java/com/ruoyi/sales/vo/ExportProcessContractVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,115 @@ package com.ruoyi.sales.vo; import com.ruoyi.basic.pojo.Customer; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.math.BigDecimal; import java.util.List; import java.util.Optional; import static com.ruoyi.common.utils.StringUtils.padRight; /** * @author buhuazhen * @date 2026/3/18 * @email 3038525872@qq.com */ @Data @AllArgsConstructor @NoArgsConstructor public class ExportProcessContractVo implements Serializable { private Long id; // yyyyå¹´MMæddæ¥ private String createTime; // æ»éé¢(大忱å) private String totalAmountZh; // ç²æ¹ private Customer partyA; // 乿¹ private Customer partyB; // ç²æ¹å ¬å¸åç§° private String partyAClientName; // 乿¹å ¬å¸åç§° private String partyBClientName; // 夿³¨ private String remark; private List<SaleProduct> saleProducts; // ç¾è®¢å°ç¹ private String placeOfSinging; private String taxRate; // å ¬å¼ä¿¡æ¯ @Data @AllArgsConstructor @NoArgsConstructor public static class Customer implements Serializable { // æ³äºº private String corporation = ""; // 弿·è¡ private String bankName = ""; //代ç人 private String agent = ""; // å°å private String address = ""; //ä¼ ç private String fax = ""; private String taxpayerIdentificationNumber = ""; // 弿·è¡å· private String bankCode = ""; // é®ç¼ private String postCode = ""; public static ExportProcessContractVo.Customer getCustomer(com.ruoyi.basic.pojo.Customer customer) { ExportProcessContractVo.Customer partyA = new ExportProcessContractVo.Customer(); partyA.setFax(Optional.ofNullable(customer.getFax()).orElse("")); partyA.setAddress(padRight(customer.getCompanyAddress(), 15)); partyA.setCorporation(Optional.ofNullable(customer.getCorporation()).orElse("")); partyA.setBankName(padRight(customer.getBankName(), 13)); partyA.setAgent(Optional.ofNullable(customer.getAgent()).orElse("")); partyA.setTaxpayerIdentificationNumber(padRight(customer.getTaxpayerIdentificationNumber(), 15)); partyA.setBankCode(padRight(customer.getBankCode(), 12)); return partyA; } } @Data @AllArgsConstructor @NoArgsConstructor public static class SaleProduct implements Serializable { // ååç¼å· private String salesContractNo = ""; private String productCategory = ""; private String specificationModel = ""; private BigDecimal quantity; // ç¨ç private BigDecimal taxRate; // å«ç¨åä»· private BigDecimal taxInclusiveUnitPrice; // å«ç¨æ»ä»· private BigDecimal taxInclusiveTotalPrice; } } src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -48,6 +48,9 @@ <if test="c.status != null and c.status != ''"> and ppm.status = #{c.status} </if> <if test="c.auditStatus != null"> and ppm.audit_status = #{c.auditStatus} </if> </where> order by ppm.id src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -61,6 +61,7 @@ T2.nick_name AS entry_person_name, T1.payment_method, T1.delivery_date, T1.place_of_singing, DATEDIFF(T1.delivery_date, CURDATE()) AS delivery_days_diff, CASE WHEN shipping_status_counts.total_count = 0 THEN false src/main/resources/static/contract_tmp.docxBinary files differ