| | |
| | | package com.ruoyi.sales.service.impl; |
| | | |
| | | import cn.hutool.core.convert.NumberChineseFormatter; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | |
| | | 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.basic.mapper.CustomerMapper; |
| | | import com.ruoyi.basic.mapper.ProductMapper; |
| | | import com.ruoyi.basic.mapper.ProductModelMapper; |
| | | import com.ruoyi.basic.pojo.Customer; |
| | | import com.ruoyi.basic.pojo.ProductModel; |
| | | import com.ruoyi.common.enums.FileNameType; |
| | | import com.ruoyi.common.enums.SaleEnum; |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.EnumUtil; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | |
| | | 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.pojo.ProductOrder; |
| | | import com.ruoyi.production.pojo.ProductProcessRouteItem; |
| | | import com.ruoyi.production.pojo.ProductWorkOrder; |
| | | import com.ruoyi.production.pojo.ProductionProductMain; |
| | | 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 lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.lang.reflect.Field; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.net.URLEncoder; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | |
| | | @Override |
| | | public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) { |
| | | return salesLedgerMapper.selectSalesLedgerList(salesLedgerDto); |
| | | } |
| | | |
| | | |
| | | public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type){ |
| | | LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); |
| | | productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, relateId); |
| | | productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); |
| | | return salesLedgerProductMapper.selectList(productWrapper); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return lossProductModelDtos; |
| | | } |
| | | |
| | | @Override |
| | | public IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page) { |
| | | IPage<SalesLedgerDto> salesLedgerDtoIPage = salesLedgerMapper.listSalesLedger(page, salesLedgerDto); |
| | | for (SalesLedgerDto salesLedger : salesLedgerDtoIPage.getRecords()) { |
| | | LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>(); |
| | | productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()); |
| | | productWrapper.eq(SalesLedgerProduct::getType, 1); |
| | | List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper); |
| | | for (SalesLedgerProduct product : products) { |
| | | product.setOriginalNoInvoiceNum(product.getNoInvoiceNum()); |
| | | // 提供临时未开票数,未开票金额供前段计算 |
| | | product.setTempnoInvoiceAmount(product.getNoInvoiceAmount()); |
| | | product.setTempNoInvoiceNum(product.getNoInvoiceNum()); |
| | | product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); |
| | | product.setRegisterDate(LocalDateTime.now()); |
| | | // 发货信息 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() |
| | | .eq(ShippingInfo::getSalesLedgerProductId, product.getId()) |
| | | .orderByDesc(ShippingInfo::getCreateTime) |
| | | .last("limit 1")); |
| | | if (shippingInfo != null) { |
| | | product.setShippingStatus(shippingInfo.getStatus()); |
| | | |
| | | } |
| | | } |
| | | if (!products.isEmpty()) { |
| | | salesLedger.setHasChildren(true); |
| | | salesLedger.setProductData(products); |
| | | } |
| | | } |
| | | |
| | | return salesLedgerDtoIPage; |
| | | } |
| | | |
| | | |
| | | // 内部类用于存储聚合结果 |
| | | private static class GroupedCustomer { |
| | |
| | | // 4. 处理子表数据 |
| | | List<SalesLedgerProduct> productList = salesLedgerDto.getProductData(); |
| | | if (productList != null && !productList.isEmpty()) { |
| | | handleSalesLedgerProducts(salesLedger.getId(), productList, salesLedgerDto.getType()); |
| | | handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class,salesLedgerDto.getType())); |
| | | updateMainContractAmount( |
| | | salesLedger.getId(), |
| | | productList, |
| | |
| | | } |
| | | |
| | | |
| | | private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) { |
| | | @Override |
| | | public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) { |
| | | // 按ID分组,区分新增和更新的记录 |
| | | Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream() |
| | | .peek(p -> p.setSalesLedgerId(salesLedgerId)) |
| | |
| | | // 执行更新操作 |
| | | if (!updateList.isEmpty()) { |
| | | for (SalesLedgerProduct product : updateList) { |
| | | product.setType(type); |
| | | product.setType(type.getCode()); |
| | | salesLedgerProductMapper.updateById(product); |
| | | } |
| | | } |
| | | // 执行插入操作 |
| | | if (!insertList.isEmpty()) { |
| | | for (SalesLedgerProduct salesLedgerProduct : insertList) { |
| | | salesLedgerProduct.setType(type); |
| | | salesLedgerProduct.setType(type.getCode()); |
| | | salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity()); |
| | | salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); |
| | | salesLedgerProductMapper.insert(salesLedgerProduct); |
| | | // 添加生产数据 |
| | | salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | // salesLedgerProductServiceImpl.addProductionData(salesLedgerProduct); |
| | | } |
| | | } |
| | | } |
| | |
| | | throw new RuntimeException("动态更新主表金额失败", e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void export(HttpServletResponse response, Long id) { |
| | | SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct(); |
| | | salesLedgerProduct.setSalesLedgerId(id); |
| | | salesLedgerProduct.setType(1); |
| | | List<SalesLedgerProduct> list = salesLedgerProductServiceImpl.selectSalesLedgerProductList(salesLedgerProduct); |
| | | List<Map<String, Object>> products = new ArrayList<>(); |
| | | BigDecimal amount = BigDecimal.ZERO; |
| | | for (int i = 0; i < list.size(); i++) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | SalesLedgerProduct product = list.get(i); |
| | | map.put("index", i + 1); |
| | | map.put("productCategory", product.getProductCategory()); |
| | | map.put("specificationModel", product.getSpecificationModel()); |
| | | map.put("unit", product.getUnit()); |
| | | map.put("quantity", product.getQuantity()); |
| | | map.put("taxInclusiveUnitPrice", product.getTaxInclusiveUnitPrice().setScale(2, RoundingMode.HALF_UP).toString()); |
| | | map.put("taxInclusiveTotalPrice", product.getTaxInclusiveTotalPrice().setScale(2, RoundingMode.HALF_UP).toString()); |
| | | map.put("batchNo", product.getBatchNo()); |
| | | // 查询凭证 |
| | | ProductModel productModel = productModelMapper.selectById(product.getProductModelId()); |
| | | if (productModel != null) { |
| | | map.put("filingCertificateNo", productModel.getFilingCertificateNo()); |
| | | } |
| | | amount = amount.add(product.getTaxInclusiveTotalPrice()); |
| | | List<ProductOrder> productOrders = productOrderMapper.selectList(new LambdaQueryWrapper<ProductOrder>() |
| | | .eq(ProductOrder::getBatchNo, product.getBatchNo())); |
| | | if (CollectionUtils.isEmpty(productOrders)) { |
| | | throw new RuntimeException("批号不存在"); |
| | | } |
| | | List<ProductWorkOrder> productWorkOrders = productWorkOrderMapper.selectList(new LambdaQueryWrapper<ProductWorkOrder>() |
| | | .eq(ProductWorkOrder::getProductOrderId, productOrders.get(0).getId())); |
| | | List<Long> ids = productWorkOrders.stream().map(ProductWorkOrder::getId).collect(Collectors.toList()); |
| | | List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(new LambdaQueryWrapper<ProductionProductMain>() |
| | | .in(ProductionProductMain::getWorkOrderId, ids) |
| | | .orderByDesc(ProductionProductMain::getCreateTime)); |
| | | List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(new LambdaQueryWrapper<ProductProcessRouteItem>() |
| | | .in(ProductProcessRouteItem::getId, productionProductMains.stream() |
| | | .map(ProductionProductMain::getProductProcessRouteItemId).collect(Collectors.toList())) |
| | | .eq(ProductProcessRouteItem::getProductModelId, product.getProductModelId()) |
| | | .orderByDesc(ProductProcessRouteItem::getCreateTime)); |
| | | if (CollectionUtils.isEmpty(productProcessRouteItems)) { |
| | | throw new RuntimeException("生产数据不存在"); |
| | | } |
| | | String productionDate = productProcessRouteItems.get(0).getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | if (productModel.getValidityPeriod() == null) { |
| | | throw new RuntimeException("有效期不能为空"); |
| | | } |
| | | String expiryDate = productProcessRouteItems.get(0).getCreateTime().plusYears(productModel.getValidityPeriod().longValue()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | map.put("productionDate", productionDate); |
| | | map.put("expiryDate", expiryDate); |
| | | products.add(map); |
| | | } |
| | | Map<String, Object> data = new HashMap<>(); |
| | | data.put("products", products); |
| | | data.put("amount", amount); |
| | | data.put("amountBig", NumberChineseFormatter.format(amount, true, false)); |
| | | SalesLedger salesLedger = salesLedgerMapper.selectById(id); |
| | | data.put("customerName ", salesLedger.getCustomerName()); |
| | | data.put("executionDate", salesLedger.getExecutionDate()); |
| | | data.put("salesContractNo", salesLedger.getSalesContractNo()); |
| | | Customer customer = customerMapper.selectById(salesLedger.getCustomerId()); |
| | | data.put("companyPhone", customer.getCompanyPhone()); |
| | | data.put("companyAddress", customer.getCompanyAddress()); |
| | | data.put("salesman", salesLedger.getSalesman()); |
| | | |
| | | InputStream inputStream = this.getClass().getResourceAsStream("/static/sale-outbound.docx"); |
| | | |
| | | LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); |
| | | |
| | | Configure config = Configure.builder() |
| | | .bind("products", policy).build(); |
| | | |
| | | XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render(data); |
| | | try { |
| | | response.setContentType("application/msword"); |
| | | String fileName = URLEncoder.encode( |
| | | "销售出库单", "UTF-8"); |
| | | response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); |
| | | response.setHeader("Content-disposition", |
| | | "attachment;filename=" + fileName + ".docx"); |
| | | OutputStream os = response.getOutputStream(); |
| | | template.write(os); |
| | | os.flush(); |
| | | os.close(); |
| | | inputStream.close(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("导出失败"); |
| | | } |
| | | |
| | | } |
| | | } |