@@ -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 ;
}
}