完善采购合同导入

This commit is contained in:
zhanghuibin 2025-11-19 17:06:50 +08:00
parent 4ecd736cbd
commit 6910611c61
7 changed files with 164 additions and 100 deletions

View File

@ -222,7 +222,7 @@ public class ConPurchaseController extends BaseController {
try { try {
return R.ok(iConPurchaseService.importPurchase(file)); return R.ok(iConPurchaseService.importPurchase(file));
} catch (Exception e) { } catch (Exception e) {
return R.fail("导入失败"); return R.fail(e.getMessage());
} }
} }
} }

View File

@ -115,6 +115,11 @@ public class ConPurchaseMedia extends BaseEntity {
*/ */
@FieldNameApi(name ="媒体费") @FieldNameApi(name ="媒体费")
private Double mediaFee; private Double mediaFee;
/**
* 媒体费单位
*/
@FieldNameApi(name ="媒体费单位")
private String mediaFeeUnit;
/** /**
* 制作费 * 制作费
*/ */

View File

@ -151,6 +151,12 @@ public class ConPurchaseMediaBo extends BaseEntity {
@CustomBaenAnnotation(value = "媒体费") @CustomBaenAnnotation(value = "媒体费")
private Double mediaFee; private Double mediaFee;
/**
* 媒体费单位
*/
@CustomBaenAnnotation(value = "媒体费单位")
private String mediaFeeUnit;
/** /**
* 制作费 * 制作费
*/ */

View File

@ -1,7 +1,10 @@
package com.ruoyi.contract.domain.vo; package com.ruoyi.contract.domain.vo;
import cn.hutool.core.annotation.Alias; import cn.hutool.core.annotation.Alias;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date; import java.util.Date;
/** /**
@ -28,9 +31,13 @@ public class ConPurchaseImportVO {
@Alias("城市") @Alias("城市")
private String cityName; private String cityName;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
@Alias("发布开始时间") @Alias("发布开始时间")
private Date startTime; private Date startTime;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
@Alias("发布结束时间") @Alias("发布结束时间")
private Date endTime; private Date endTime;
@ -74,21 +81,23 @@ public class ConPurchaseImportVO {
private String firstName; private String firstName;
@Alias("供应商名称") @Alias("供应商名称")
private String supplierName; private String secondName;
@Alias("媒介部门") @Alias("媒介部门")
private String mediaDeptName; private String mediaDeptName;
@Alias("发票类型") @Alias("发票类型")
private String invoiceType; private String invoiceName;
@Alias("税率") @Alias("税率")
private String taxRate; private String taxPoints;
@Alias("发票内容") @Alias("发票内容")
private String invoiceContent; private String invoiceContent;
@Alias("签订日期") @Alias("签订日期")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date signTime; private Date signTime;
@Alias("合同附件") @Alias("合同附件")

View File

@ -106,5 +106,5 @@ public interface IConPurchaseService {
* @return 结果 * @return 结果
* @throws Exception * @throws Exception
*/ */
int importPurchase(MultipartFile file); int importPurchase(MultipartFile file) throws Exception;
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader; import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.ExcelUtil;
@ -22,6 +23,7 @@ import com.ruoyi.common.utils.sql.HeadExcelUtils;
import com.ruoyi.contract.domain.*; import com.ruoyi.contract.domain.*;
import com.ruoyi.contract.domain.bo.*; import com.ruoyi.contract.domain.bo.*;
import com.ruoyi.contract.domain.bo.conpurchase.ConPurchaseBoExtend; import com.ruoyi.contract.domain.bo.conpurchase.ConPurchaseBoExtend;
import com.ruoyi.contract.domain.dto.ConSaleImportDto;
import com.ruoyi.contract.domain.vo.*; import com.ruoyi.contract.domain.vo.*;
import com.ruoyi.contract.domain.vo.conpurchasevo.ConPurchaseTotalVo; import com.ruoyi.contract.domain.vo.conpurchasevo.ConPurchaseTotalVo;
import com.ruoyi.contract.mapper.*; import com.ruoyi.contract.mapper.*;
@ -125,125 +127,166 @@ public class ConPurchaseServiceImpl implements IConPurchaseService {
@Resource @Resource
private Validator validator; private Validator validator;
/**
* 导入采购合同信息
* @param file 导入文件
* @return
* @throws Exception
*/
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public int importPurchase(MultipartFile file) { public int importPurchase(MultipartFile file) throws Exception {
List<ConPurchaseImportVO> list; ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
try (InputStream inputStream = file.getInputStream()) { List<ConPurchaseImportVO> list = reader.readAll(ConPurchaseImportVO.class);
ExcelReader reader = ExcelUtil.getReader(inputStream); reader.close();
list = reader.readAll(ConPurchaseImportVO.class);
} catch (IOException e) {
throw new ServiceException("导入采购合同失败");
}
if (CollectionUtil.isEmpty(list)) { if (CollectionUtil.isEmpty(list)) {
throw new ServiceException("导入数据不能为空"); throw new ServiceException("导入数据不能为空");
} }
for (int i = 0; i < list.size(); i++) { // 按合同编号对导入数据进行分组
ConPurchaseImportVO vo = list.get(i); Map<String, List<ConPurchaseImportVO>> mapByContractNumber = list.stream()
try { .filter(vo -> StringUtils.isNotBlank(vo.getContractNumber()))
// 校验必填项 .collect(Collectors.groupingBy(ConPurchaseImportVO::getContractNumber));
if (StringUtils.isBlank(vo.getContractNumber())) {
throw new ServiceException("合同编号不能为空"); // 遍历每个合同分组
for (Map.Entry<String, List<ConPurchaseImportVO>> entry : mapByContractNumber.entrySet()) {
String contractNumber = entry.getKey();
List<ConPurchaseImportVO> rows = entry.getValue();
ConPurchaseImportVO firstRow = rows.get(0); // 使用第一行数据作为主信息
// 判断合同是否存在
ConPurchase existingContract = baseMapper.selectOne(new LambdaQueryWrapper<ConPurchase>()
.eq(ConPurchase::getContractNumber, contractNumber));
if (existingContract == null) {
// 合同不存在 -> 调用 insertByBo 新增
ConPurchaseBo purchaseBo = new ConPurchaseBo();
// 手动映射主表字段
purchaseBo.setContractNumber(firstRow.getContractNumber());
purchaseBo.setProjNumber(firstRow.getProjNumber());
purchaseBo.setProjName(firstRow.getProjName());
purchaseBo.setStartTime(firstRow.getStartTime());
purchaseBo.setEndTime(firstRow.getEndTime());
purchaseBo.setContractMoney(firstRow.getContractMoney());
purchaseBo.setInvoiceContent(firstRow.getInvoiceContent());
purchaseBo.setSignTime(firstRow.getSignTime());
purchaseBo.setUpPrint(firstRow.getUpPrint());
purchaseBo.setExchangePrint(firstRow.getExchangePrint());
purchaseBo.setNextPrint(firstRow.getNextPrint());
purchaseBo.setMediaLink(firstRow.getMediaLink());
purchaseBo.setFirstName(firstRow.getFirstName());
purchaseBo.setMediaDeptName(firstRow.getMediaDeptName());
purchaseBo.setSecondName(firstRow.getSecondName()); // 供应商名称乙方名称
purchaseBo.setTaxPoints(firstRow.getTaxPoints()); // 税率税点
purchaseBo.setMediaLink(firstRow.getMediaLink());
// 状态转换
String state = "生效".equals(firstRow.getState()) ? "1" : "0";
purchaseBo.setState(state);
// 关联客户ID
if (StringUtils.isNotBlank(firstRow.getClientName())) {
ConClient conClient = conClientMapper.selectOne(new LambdaQueryWrapper<ConClient>().eq(ConClient::getClientName, firstRow.getClientName()));
if (conClient != null) {
purchaseBo.setClientId(conClient.getId());
}
} }
ConPurchase conPurchase = baseMapper.selectOne(new LambdaQueryWrapper<ConPurchase>() // 关联甲方ID
.eq(ConPurchase::getContractNumber, vo.getContractNumber())); if (StringUtils.isNotBlank(firstRow.getFirstName())) {
ConFirst conFirst = conFirstMapper.selectOne(new LambdaQueryWrapper<ConFirst>().eq(ConFirst::getFirstName, firstRow.getFirstName()));
if (conPurchase == null) {
// 不存在新增合同
conPurchase = new ConPurchase();
// 手动进行字段映射
conPurchase.setContractNumber(vo.getContractNumber());
conPurchase.setProjNumber(vo.getProjNumber());
conPurchase.setProjName(vo.getProjName());
conPurchase.setStartTime(vo.getStartTime());
conPurchase.setEndTime(vo.getEndTime());
conPurchase.setContractMoney(vo.getContractMoney());
conPurchase.setInvoiceContent(vo.getInvoiceContent());
conPurchase.setSignTime(vo.getSignTime());
conPurchase.setUpPrint(vo.getUpPrint());
conPurchase.setExchangePrint(vo.getExchangePrint());
conPurchase.setNextPrint(vo.getNextPrint());
conPurchase.setMediaLink(vo.getMediaLink());
String state = "生效".equals(vo.getState()) ? "1" : "0";
conPurchase.setState(state);
conPurchase.setFirstName(vo.getFirstName());
conPurchase.setMediaDeptName(vo.getMediaDeptName());
// 供应商名称乙方名称
conPurchase.setSecondName(vo.getSupplierName());
//税率税点
conPurchase.setTaxPoints(vo.getTaxRate());
//甲方
if (StringUtils.isNotBlank(vo.getFirstName())) {
ConFirst conFirst = conFirstMapper.selectOne(new LambdaQueryWrapper<ConFirst>().eq(ConFirst::getFirstName, vo.getFirstName()));
if (conFirst != null) { if (conFirst != null) {
conPurchase.setFirstId(conFirst.getId()); purchaseBo.setFirstId(conFirst.getId());
} }
} }
//媒介部门 // 关联媒介部门ID
if (StringUtils.isNotBlank(vo.getMediaDeptName())) { if (StringUtils.isNotBlank(firstRow.getMediaDeptName())) {
ConMediaDept conMediaDept = conMediaDeptMapper.selectOne(new LambdaQueryWrapper<ConMediaDept>().eq(ConMediaDept::getMediaDeptName, vo.getMediaDeptName())); ConMediaDept conMediaDept = conMediaDeptMapper.selectOne(new LambdaQueryWrapper<ConMediaDept>().eq(ConMediaDept::getMediaDeptName, firstRow.getMediaDeptName()));
if (conMediaDept != null) { if (conMediaDept != null) {
conPurchase.setMediaDeptId(conMediaDept.getId()); purchaseBo.setMediaDeptId(conMediaDept.getId());
} }
} }
//发票类型 // 关联发票类型ID
if (StringUtils.isNotBlank(vo.getInvoiceType())) { if (StringUtils.isNotBlank(firstRow.getInvoiceName())) {
ConInvoice conInvoice = conInvoiceMapper.selectOne(new LambdaQueryWrapper<ConInvoice>().eq(ConInvoice::getInvoiceName, vo.getInvoiceType())); ConInvoice conInvoice = conInvoiceMapper.selectOne(new LambdaQueryWrapper<ConInvoice>().eq(ConInvoice::getInvoiceName, firstRow.getInvoiceName()));
if (conInvoice != null) { if (conInvoice != null) {
conPurchase.setInvoiceId(conInvoice.getId()); purchaseBo.setInvoiceId(conInvoice.getId());
} }
} }
validEntityBeforeSave(conPurchase); // 映射媒体子表信息
baseMapper.insert(conPurchase); List<ConPurchaseMediaBo> mediaBoList = rows.stream().map(row -> {
ConPurchaseMediaBo mediaBo = new ConPurchaseMediaBo();
this.mapRowToMediaBo(row, mediaBo);
return mediaBo;
}).collect(Collectors.toList());
purchaseBo.setPurchaseMediaBoList(mediaBoList);
this.insertByBo(purchaseBo);
} else {
// 合同已存在 -> 调用 updateByBo 追加媒体信息
ConPurchaseVo existingVo = this.queryById(existingContract.getId());
ConPurchaseBo purchaseBo = BeanUtil.toBean(existingVo, ConPurchaseBo.class);
// 获取已有的媒体信息
List<ConPurchaseMediaBo> existingMedia = purchaseBo.getPurchaseMediaBoList();
if (existingMedia == null) {
existingMedia = new ArrayList<>();
} }
// 新增媒体数据 // 创建并添加本次导入的新媒体信息
ConPurchaseMedia conPurchaseMedia = new ConPurchaseMedia(); List<ConPurchaseMediaBo> newMediaList = rows.stream().map(row -> {
conPurchaseMedia.setPurchaseId(conPurchase.getId()); ConPurchaseMediaBo mediaBo = new ConPurchaseMediaBo();
this.mapRowToMediaBo(row, mediaBo);
return mediaBo;
}).collect(Collectors.toList());
existingMedia.addAll(newMediaList);
purchaseBo.setPurchaseMediaBoList(existingMedia);
// 媒体类型 this.updateByBo(purchaseBo);
if (StringUtils.isNotBlank(vo.getMediaType())) {
ConMediaType conMediaType = conMediaTypeMapper.selectOne(new LambdaQueryWrapper<ConMediaType>().eq(ConMediaType::getMediaType, vo.getMediaType()));
if (conMediaType != null) {
conPurchaseMedia.setMediaId(conMediaType.getId());
}
}
//城市
if (StringUtils.isNotBlank(vo.getCityName())) {
ConCity conCity = conCityMapper.selectList(new LambdaQueryWrapper<ConCity>().likeRight(ConCity::getCityName, vo.getCityName())).stream().findFirst().orElse(null);
if (conCity != null) {
conPurchaseMedia.setCityId(conCity.getId());
String cityIds = iConCityService.selectTreeIds(conCity.getId());
conPurchaseMedia.setCityIds(cityIds);
}
}
conPurchaseMedia.setMediaPosition(vo.getMediaLocation());
conPurchaseMedia.setAccountNumber(safeParseDouble(vo.getPurchaseQuantity()));
conPurchaseMedia.setReleaseFrequency(vo.getFrequency());
conPurchaseMedia.setUpTime(vo.getStartTime());
conPurchaseMedia.setDownTime(vo.getEndTime());
conPurchaseMedia.setPeriod(safeParseDouble(vo.getPublishDays()));
conPurchaseMedia.setPrintPrice(safeParseDouble(vo.getListPrice()));
conPurchaseMedia.setPrintPriceUnit(vo.getListPriceUnit());
conPurchaseMedia.setDiscount(vo.getDiscount());
conPurchaseMedia.setMediaFee(safeParseDouble(vo.getNetPrice()));
conPurchaseMedia.setProductFee(safeParseDouble(vo.getProductionFee()));
conPurchaseMediaMapper.insert(conPurchaseMedia);
} catch (Exception e) {
log.error("导入采购合同失败", e);
} }
} }
return list.size(); return list.size();
} }
/**
* 辅助方法将导入行数据映射到媒体BO
*/
private void mapRowToMediaBo(ConPurchaseImportVO row, ConPurchaseMediaBo mediaBo) {
// 媒体类型
if (StringUtils.isNotBlank(row.getMediaType())) {
ConMediaType conMediaType = conMediaTypeMapper.selectOne(new LambdaQueryWrapper<ConMediaType>().eq(ConMediaType::getMediaType, row.getMediaType()));
if (conMediaType != null) {
mediaBo.setMediaId(conMediaType.getId());
mediaBo.setMediaName(conMediaType.getMediaType());
}
}
// 城市
if (StringUtils.isNotBlank(row.getCityName())) {
ConCity conCity = conCityMapper.selectList(new LambdaQueryWrapper<ConCity>().likeRight(ConCity::getCityName, row.getCityName())).stream().findFirst().orElse(null);
if (conCity != null) {
mediaBo.setCityId(conCity.getId());
mediaBo.setCityName(conCity.getCityName());
String cityIds = iConCityService.selectTreeIds(conCity.getId());
mediaBo.setCityIds(cityIds);
}
}
mediaBo.setMediaPosition(row.getMediaLocation());
mediaBo.setAccountNumber(safeParseDouble(row.getPurchaseQuantity()));
mediaBo.setReleaseFrequency(row.getFrequency());
mediaBo.setUpTime(row.getStartTime());
mediaBo.setDownTime(row.getEndTime());
mediaBo.setPeriod(safeParseDouble(row.getPublishDays()));
mediaBo.setPrintPrice(safeParseDouble(row.getListPrice()));
mediaBo.setPrintPriceUnit(row.getListPriceUnit());
mediaBo.setDiscount(StrUtil.isNotBlank(row.getDiscount()) ? row.getDiscount() : "0");
mediaBo.setMediaFee(safeParseDouble(row.getNetPrice()));
mediaBo.setMediaFeeUnit(row.getNetPriceUnit());
mediaBo.setProductFee(safeParseDouble(row.getProductionFee()));
}
private Double safeParseDouble(String str) { private Double safeParseDouble(String str) {
if (StringUtils.isBlank(str) || "-".equals(str)) { if (StringUtils.isBlank(str) || "-".equals(str)) {
return null; return null;

View File

@ -18,6 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="printPriceUnit" column="print_price_unit"/> <result property="printPriceUnit" column="print_price_unit"/>
<result property="discount" column="discount"/> <result property="discount" column="discount"/>
<result property="mediaFee" column="media_fee"/> <result property="mediaFee" column="media_fee"/>
<result property="mediaFeeUnit" column="media_fee_unit"/>
<result property="productFee" column="product_fee"/> <result property="productFee" column="product_fee"/>
<result property="createBy" column="create_by"/> <result property="createBy" column="create_by"/>
<result property="createUserId" column="create_user_id"/> <result property="createUserId" column="create_user_id"/>