1
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package com.ruoyi.jarvis.domain;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 后返/跟团返现 Excel 上传记录
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GroupRebateExcelUpload extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String documentTitle;
|
||||
private String originalFilename;
|
||||
/** 若依资源路径,如 /profile/upload/group-rebate-excel/... */
|
||||
private String filePath;
|
||||
private Long fileSize;
|
||||
/** 1 解析失败或未处理 2 已成功解析并写订单 */
|
||||
private Integer importStatus;
|
||||
private Integer dataRows;
|
||||
private Integer updatedOrders;
|
||||
private Integer notFoundCount;
|
||||
private String resultDetailJson;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.jarvis.mapper;
|
||||
|
||||
import com.ruoyi.jarvis.domain.GroupRebateExcelUpload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GroupRebateExcelUploadMapper {
|
||||
|
||||
int insertGroupRebateExcelUpload(GroupRebateExcelUpload row);
|
||||
|
||||
GroupRebateExcelUpload selectGroupRebateExcelUploadById(Long id);
|
||||
|
||||
List<GroupRebateExcelUpload> selectGroupRebateExcelUploadList(GroupRebateExcelUpload query);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.ruoyi.jarvis.service;
|
||||
|
||||
import com.ruoyi.jarvis.domain.GroupRebateExcelUpload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IGroupRebateExcelUploadService {
|
||||
|
||||
/**
|
||||
* 独立事务写入上传记录(导入主流程回滚时仍保留审计记录)
|
||||
*/
|
||||
void saveRecordInNewTransaction(GroupRebateExcelUpload row);
|
||||
|
||||
GroupRebateExcelUpload selectGroupRebateExcelUploadById(Long id);
|
||||
|
||||
List<GroupRebateExcelUpload> selectGroupRebateExcelUploadList(GroupRebateExcelUpload query);
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
package com.ruoyi.jarvis.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.config.RuoYiConfig;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.jarvis.domain.GroupRebateExcelUpload;
|
||||
import com.ruoyi.jarvis.domain.JDOrder;
|
||||
import com.ruoyi.jarvis.domain.dto.RebateRemarkItem;
|
||||
import com.ruoyi.jarvis.mapper.JDOrderMapper;
|
||||
import com.ruoyi.jarvis.service.IGroupRebateExcelUploadService;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
@@ -13,11 +21,15 @@ import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -30,7 +42,7 @@ import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 解析跟团返现类 Excel(表头含单号、是否返现、返现金额等),写入订单后返备注 JSON。
|
||||
* 解析跟团返现类 Excel(表头含单号、是否返现、返现金额等),写入订单后返备注 JSON;并保存上传文件与数据库记录。
|
||||
*/
|
||||
@Service
|
||||
public class GroupRebateExcelImportService {
|
||||
@@ -39,6 +51,8 @@ public class GroupRebateExcelImportService {
|
||||
|
||||
private static final DataFormatter DATA_FORMATTER = new DataFormatter();
|
||||
|
||||
private static final String[] EXCEL_EXT = { "xls", "xlsx" };
|
||||
|
||||
private static final Pattern ABNORMAL_HINT = Pattern.compile(
|
||||
".*(异常|待补|待返|下次|驳回|未返|不返|暂缓|缺|补表|重做|暂无|无$|-).*", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
@@ -48,29 +62,73 @@ public class GroupRebateExcelImportService {
|
||||
@Resource
|
||||
private JDOrderMapper jdOrderMapper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Resource
|
||||
private IGroupRebateExcelUploadService groupRebateExcelUploadService;
|
||||
|
||||
private GroupRebateExcelImportService self;
|
||||
|
||||
@Autowired
|
||||
public void setSelf(@Lazy GroupRebateExcelImportService self) {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
/**
|
||||
* 先落盘上传文件,再解析写订单;无论成败均写入上传记录(独立事务)。
|
||||
*/
|
||||
public Map<String, Object> importExcel(MultipartFile file, String documentTitle) throws Exception {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
String originalFilename = file != null ? file.getOriginalFilename() : null;
|
||||
long fileSize = file != null ? file.getSize() : 0L;
|
||||
String title = resolveDocumentTitle(file, documentTitle);
|
||||
String webPath = "";
|
||||
|
||||
if (file == null || file.isEmpty()) {
|
||||
result.put("success", false);
|
||||
result.put("message", "请选择文件");
|
||||
return result;
|
||||
}
|
||||
String title = documentTitle != null ? documentTitle.trim() : "";
|
||||
if (title.isEmpty()) {
|
||||
String name = file.getOriginalFilename();
|
||||
if (name != null && name.contains(".")) {
|
||||
title = name.substring(0, name.lastIndexOf('.'));
|
||||
} else {
|
||||
title = name != null ? name : "未命名文档";
|
||||
}
|
||||
Map<String, Object> empty = new HashMap<>();
|
||||
empty.put("success", false);
|
||||
empty.put("message", "请选择文件");
|
||||
empty.put("documentTitle", title);
|
||||
persistUploadRecord(originalFilename, webPath, fileSize, title, empty);
|
||||
return empty;
|
||||
}
|
||||
|
||||
try (InputStream is = file.getInputStream(); Workbook wb = WorkbookFactory.create(is)) {
|
||||
try {
|
||||
String baseDir = RuoYiConfig.getUploadPath() + File.separator + "group-rebate-excel";
|
||||
webPath = FileUploadUtils.upload(baseDir, file, EXCEL_EXT);
|
||||
} catch (Exception e) {
|
||||
log.warn("保存后返Excel失败", e);
|
||||
Map<String, Object> fail = new HashMap<>();
|
||||
fail.put("success", false);
|
||||
fail.put("message", "保存上传文件失败: " + e.getMessage());
|
||||
fail.put("documentTitle", title);
|
||||
persistUploadRecord(originalFilename, webPath, fileSize, title, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
File diskFile = resolveDiskFile(webPath);
|
||||
Map<String, Object> result;
|
||||
try {
|
||||
result = self.processWorkbookTransactional(diskFile, title);
|
||||
} catch (Exception e) {
|
||||
log.error("后返表导入处理异常", e);
|
||||
result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "导入处理异常: " + e.getMessage());
|
||||
result.put("documentTitle", title);
|
||||
}
|
||||
result.put("savedFilePath", webPath);
|
||||
Long recordId = persistUploadRecord(originalFilename, webPath, fileSize, title, result);
|
||||
result.put("uploadRecordId", recordId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> processWorkbookTransactional(File diskFile, String title) throws Exception {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try (InputStream is = new FileInputStream(diskFile); Workbook wb = WorkbookFactory.create(is)) {
|
||||
Sheet sheet = wb.getNumberOfSheets() > 0 ? wb.getSheetAt(0) : null;
|
||||
if (sheet == null) {
|
||||
result.put("success", false);
|
||||
result.put("message", "工作簿无工作表");
|
||||
result.put("documentTitle", title);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -78,6 +136,7 @@ public class GroupRebateExcelImportService {
|
||||
if (headerRowIndex < 0) {
|
||||
result.put("success", false);
|
||||
result.put("message", "未找到表头(需包含「单号」或「订单号」列,以及「是否返现」或「总共返现」相关列)");
|
||||
result.put("documentTitle", title);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -86,11 +145,13 @@ public class GroupRebateExcelImportService {
|
||||
if (hm.orderCol < 0) {
|
||||
result.put("success", false);
|
||||
result.put("message", "未识别订单号列(表头需含「单号」或「订单号」,不含「第三方」)");
|
||||
result.put("documentTitle", title);
|
||||
return result;
|
||||
}
|
||||
if (hm.whetherRebateCol < 0 && hm.totalCashbackCol < 0) {
|
||||
result.put("success", false);
|
||||
result.put("message", "未识别「是否返现」或返现金额列(如「总共返现」)");
|
||||
result.put("documentTitle", title);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -154,6 +215,90 @@ public class GroupRebateExcelImportService {
|
||||
}
|
||||
}
|
||||
|
||||
private Long persistUploadRecord(String originalFilename, String webPath, long fileSize,
|
||||
String title, Map<String, Object> procResult) {
|
||||
GroupRebateExcelUpload row = new GroupRebateExcelUpload();
|
||||
row.setOriginalFilename(originalFilename);
|
||||
row.setFilePath(StringUtils.isNotEmpty(webPath) ? webPath : "");
|
||||
row.setFileSize(fileSize);
|
||||
row.setDocumentTitle(title);
|
||||
try {
|
||||
row.setCreateBy(SecurityUtils.getUsername());
|
||||
} catch (Exception e) {
|
||||
row.setCreateBy("");
|
||||
}
|
||||
boolean ok = Boolean.TRUE.equals(procResult.get("success"));
|
||||
row.setImportStatus(ok ? 2 : 1);
|
||||
row.setDataRows(asInt(procResult.get("dataRows")));
|
||||
row.setUpdatedOrders(asInt(procResult.get("updatedOrders")));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> nf = (List<String>) procResult.get("notFoundOrderNos");
|
||||
row.setNotFoundCount(nf != null ? nf.size() : null);
|
||||
|
||||
JSONObject detail = new JSONObject();
|
||||
detail.put("message", procResult.get("message"));
|
||||
detail.put("documentTitle", procResult.get("documentTitle"));
|
||||
if (procResult.containsKey("notFoundOrderNos")) {
|
||||
detail.put("notFoundOrderNos", procResult.get("notFoundOrderNos"));
|
||||
}
|
||||
if (procResult.containsKey("errors")) {
|
||||
detail.put("errors", procResult.get("errors"));
|
||||
}
|
||||
if (procResult.containsKey("savedFilePath")) {
|
||||
detail.put("savedFilePath", procResult.get("savedFilePath"));
|
||||
}
|
||||
row.setResultDetailJson(detail.toJSONString());
|
||||
|
||||
try {
|
||||
groupRebateExcelUploadService.saveRecordInNewTransaction(row);
|
||||
return row.getId();
|
||||
} catch (Exception e) {
|
||||
log.error("写入后返上传记录失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer asInt(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
}
|
||||
if (o instanceof Number) {
|
||||
return ((Number) o).intValue();
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(o.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String resolveDocumentTitle(MultipartFile file, String documentTitle) {
|
||||
String t = documentTitle != null ? documentTitle.trim() : "";
|
||||
if (!t.isEmpty()) {
|
||||
return t;
|
||||
}
|
||||
if (file == null) {
|
||||
return "未命名文档";
|
||||
}
|
||||
String name = file.getOriginalFilename();
|
||||
if (name != null && name.contains(".")) {
|
||||
return name.substring(0, name.lastIndexOf('.'));
|
||||
}
|
||||
return name != null ? name : "未命名文档";
|
||||
}
|
||||
|
||||
/** 将 /profile/... 转为本地 File */
|
||||
public static File resolveDiskFile(String webPath) {
|
||||
if (StringUtils.isEmpty(webPath)) {
|
||||
throw new IllegalArgumentException("file path empty");
|
||||
}
|
||||
String sub = StringUtils.substringAfter(webPath, Constants.RESOURCE_PREFIX);
|
||||
if (sub.startsWith("/")) {
|
||||
sub = sub.substring(1);
|
||||
}
|
||||
return new File(RuoYiConfig.getProfile(), sub);
|
||||
}
|
||||
|
||||
private void appendRebateRemark(JDOrder order, String documentTitle, String whetherRebate, String rebateAmount) {
|
||||
List<RebateRemarkItem> list = new ArrayList<>();
|
||||
String existing = order.getRebateRemarkJson();
|
||||
@@ -342,7 +487,6 @@ public class GroupRebateExcelImportService {
|
||||
int orderCol = -1;
|
||||
int whetherRebateCol = -1;
|
||||
int totalCashbackCol = -1;
|
||||
/** 无「总共返现」时的备选:含「返现」「金额」的列 */
|
||||
int fallbackAmountCol = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruoyi.jarvis.service.impl;
|
||||
|
||||
import com.ruoyi.jarvis.domain.GroupRebateExcelUpload;
|
||||
import com.ruoyi.jarvis.mapper.GroupRebateExcelUploadMapper;
|
||||
import com.ruoyi.jarvis.service.IGroupRebateExcelUploadService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class GroupRebateExcelUploadServiceImpl implements IGroupRebateExcelUploadService {
|
||||
|
||||
@Resource
|
||||
private GroupRebateExcelUploadMapper groupRebateExcelUploadMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void saveRecordInNewTransaction(GroupRebateExcelUpload row) {
|
||||
groupRebateExcelUploadMapper.insertGroupRebateExcelUpload(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupRebateExcelUpload selectGroupRebateExcelUploadById(Long id) {
|
||||
return groupRebateExcelUploadMapper.selectGroupRebateExcelUploadById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupRebateExcelUpload> selectGroupRebateExcelUploadList(GroupRebateExcelUpload query) {
|
||||
return groupRebateExcelUploadMapper.selectGroupRebateExcelUploadList(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.jarvis.mapper.GroupRebateExcelUploadMapper">
|
||||
|
||||
<resultMap id="GroupRebateExcelUploadResult" type="GroupRebateExcelUpload">
|
||||
<id property="id" column="id"/>
|
||||
<result property="documentTitle" column="document_title"/>
|
||||
<result property="originalFilename" column="original_filename"/>
|
||||
<result property="filePath" column="file_path"/>
|
||||
<result property="fileSize" column="file_size"/>
|
||||
<result property="importStatus" column="import_status"/>
|
||||
<result property="dataRows" column="data_rows"/>
|
||||
<result property="updatedOrders" column="updated_orders"/>
|
||||
<result property="notFoundCount" column="not_found_count"/>
|
||||
<result property="resultDetailJson" column="result_detail_json"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCols">
|
||||
select id, document_title, original_filename, file_path, file_size, import_status,
|
||||
data_rows, updated_orders, not_found_count, result_detail_json, create_by, create_time
|
||||
from jd_group_rebate_excel_upload
|
||||
</sql>
|
||||
|
||||
<insert id="insertGroupRebateExcelUpload" parameterType="GroupRebateExcelUpload" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into jd_group_rebate_excel_upload (
|
||||
document_title, original_filename, file_path, file_size, import_status,
|
||||
data_rows, updated_orders, not_found_count, result_detail_json, create_by, create_time
|
||||
) values (
|
||||
#{documentTitle}, #{originalFilename}, #{filePath}, #{fileSize}, #{importStatus},
|
||||
#{dataRows}, #{updatedOrders}, #{notFoundCount}, #{resultDetailJson}, #{createBy}, now()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<select id="selectGroupRebateExcelUploadById" parameterType="long" resultMap="GroupRebateExcelUploadResult">
|
||||
<include refid="selectCols"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="selectGroupRebateExcelUploadList" parameterType="GroupRebateExcelUpload" resultMap="GroupRebateExcelUploadResult">
|
||||
<include refid="selectCols"/>
|
||||
<where>
|
||||
<if test="documentTitle != null and documentTitle != ''">
|
||||
and document_title like concat('%', #{documentTitle}, '%')
|
||||
</if>
|
||||
<if test="originalFilename != null and originalFilename != ''">
|
||||
and original_filename like concat('%', #{originalFilename}, '%')
|
||||
</if>
|
||||
<if test="importStatus != null">
|
||||
and import_status = #{importStatus}
|
||||
</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''">
|
||||
and date(create_time) >= #{params.beginTime}
|
||||
</if>
|
||||
<if test="params.endTime != null and params.endTime != ''">
|
||||
and date(create_time) <= #{params.endTime}
|
||||
</if>
|
||||
</where>
|
||||
order by id desc
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user