Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ea84bfad | ||
|
|
61b8819057 | ||
|
|
01921f7fcf | ||
|
|
465a3257b5 |
@@ -133,6 +133,38 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.websocket</groupId>
|
||||||
|
<artifactId>javax.websocket-api</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-el</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-jasper</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.nutz</groupId>
|
<groupId>org.nutz</groupId>
|
||||||
<artifactId>nutzboot-parent</artifactId>
|
<artifactId>nutzboot-parent</artifactId>
|
||||||
@@ -151,6 +183,7 @@
|
|||||||
<easypoi.version>4.5.0</easypoi.version>
|
<easypoi.version>4.5.0</easypoi.version>
|
||||||
<jsoup.veision>1.15.3</jsoup.veision>
|
<jsoup.veision>1.15.3</jsoup.veision>
|
||||||
<mysql-connector-java.version>8.0.28</mysql-connector-java.version>
|
<mysql-connector-java.version>8.0.28</mysql-connector-java.version>
|
||||||
|
<tomcat.version>9.0.121</tomcat.version>
|
||||||
<sa-token.version>1.25.0</sa-token.version>
|
<sa-token.version>1.25.0</sa-token.version>
|
||||||
<easy-captcha.version>1.6.2</easy-captcha.version>
|
<easy-captcha.version>1.6.2</easy-captcha.version>
|
||||||
<emoji-java.veision>4.0.0</emoji-java.veision>
|
<emoji-java.veision>4.0.0</emoji-java.veision>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<nutzboot.version>2.6.0-SNAPSHOT</nutzboot.version>
|
<nutzboot.version>2.6.0-SNAPSHOT</nutzboot.version>
|
||||||
<nutz.version>1.r.70-SNAPSHOT</nutz.version>
|
<nutz.version>1.r.70-SNAPSHOT</nutz.version>
|
||||||
|
<tomcat.version>9.0.121</tomcat.version>
|
||||||
<mysql-connector-java.version>8.0.28</mysql-connector-java.version>
|
<mysql-connector-java.version>8.0.28</mysql-connector-java.version>
|
||||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||||
<slf4j.version>2.0.8</slf4j.version>
|
<slf4j.version>2.0.8</slf4j.version>
|
||||||
@@ -144,8 +145,22 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.nutz</groupId>
|
<groupId>org.nutz</groupId>
|
||||||
<artifactId>nutzboot-starter-jetty</artifactId>
|
<artifactId>nutzboot-starter-tomcat</artifactId>
|
||||||
<version>${nutzboot.version}</version>
|
<version>${nutzboot.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.gandon.tomcat</groupId>
|
||||||
|
<artifactId>juli-to-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.nutz</groupId>
|
||||||
|
<artifactId>nutz-plugins-websocket</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.nutz</groupId>
|
<groupId>org.nutz</groupId>
|
||||||
@@ -424,6 +439,40 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Servlet API 由 Tomcat 提供,防止旧 API 混入可执行 JAR。 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.websocket</groupId>
|
||||||
|
<artifactId>javax.websocket-api</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- 显式覆盖导入的 NutzBoot BOM,避免回退到其默认 Tomcat 8.5。 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-el</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-jasper</artifactId>
|
||||||
|
<version>${tomcat.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.nutz</groupId>
|
<groupId>org.nutz</groupId>
|
||||||
<artifactId>nutzboot-parent</artifactId>
|
<artifactId>nutzboot-parent</artifactId>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.budwk.app.web.commons.auth.satoken.SaTokenDaoRedisImpl;
|
|||||||
import com.budwk.app.web.commons.auth.satoken.StpInterfaceImpl;
|
import com.budwk.app.web.commons.auth.satoken.StpInterfaceImpl;
|
||||||
import com.budwk.app.web.commons.base.Globals;
|
import com.budwk.app.web.commons.base.Globals;
|
||||||
import com.budwk.app.web.commons.ext.pubsub.WebPubSub;
|
import com.budwk.app.web.commons.ext.pubsub.WebPubSub;
|
||||||
|
import com.budwk.app.web.commons.ext.handler.WkTomcatConfiguration;
|
||||||
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
|
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.beetl.core.GroupTemplate;
|
import org.beetl.core.GroupTemplate;
|
||||||
@@ -65,6 +66,7 @@ public class MainLauncher {
|
|||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
NbApp nb = new NbApp().setArgs(args).setPrintProcDoc(true);
|
NbApp nb = new NbApp().setArgs(args).setPrintProcDoc(true);
|
||||||
nb.getAppContext().setMainPackage("com.budwk");
|
nb.getAppContext().setMainPackage("com.budwk");
|
||||||
|
nb.addListener(new WkTomcatConfiguration());
|
||||||
nb.run();
|
nb.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,15 @@ public class FlowTodoCenterController {
|
|||||||
return Result.success(pagination);
|
return Result.success(pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询当前用户的已办任务,仅返回列表展示及详情跳转所需的信息。
|
||||||
|
*
|
||||||
|
* @param pageNumber 查询页码
|
||||||
|
* @param pageSize 每页记录数
|
||||||
|
* @param searchKeyword 流程名称查询关键字
|
||||||
|
* @param category 流程分类
|
||||||
|
* @return 已办任务分页结果,不包含完整流程变量和任务表单数据
|
||||||
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckLogin
|
@SaCheckLogin
|
||||||
public Result done(Integer pageNumber, Integer pageSize, String searchKeyword, String category) {
|
public Result done(Integer pageNumber, Integer pageSize, String searchKeyword, String category) {
|
||||||
@@ -106,8 +115,13 @@ public class FlowTodoCenterController {
|
|||||||
t.h5FormKey,
|
t.h5FormKey,
|
||||||
t.createdAt,
|
t.createdAt,
|
||||||
t.finishTime,
|
t.finishTime,
|
||||||
t.variable AS taskVariable,
|
-- 保留任务变量字段类型,但已办列表不返回其中的业务表单数据。
|
||||||
ins.variable,
|
'{}' AS taskVariable,
|
||||||
|
-- 列表仅需流程名称和申请人,避免完整变量中的身份证等信息泄露。
|
||||||
|
JSON_OBJECT(
|
||||||
|
'instanceName', ins.variable -> '$.instanceName',
|
||||||
|
'initiatorName', ins.variable -> '$.initiatorName'
|
||||||
|
) AS variable,
|
||||||
ins.state AS instanceState,
|
ins.state AS instanceState,
|
||||||
ins.id AS instanceId,
|
ins.id AS instanceId,
|
||||||
ins.businessNo,
|
ins.businessNo,
|
||||||
|
|||||||
@@ -411,15 +411,6 @@ public class Sys_user extends BaseModel implements Serializable {
|
|||||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
private String openId;
|
private String openId;
|
||||||
|
|
||||||
@Column("virtual_id")
|
|
||||||
@Comment("虚拟用户ID")
|
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 64)
|
|
||||||
private String virtualId;
|
|
||||||
|
|
||||||
@Column("virtual_org_id")
|
|
||||||
@Comment("虚拟组织ID")
|
|
||||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
|
||||||
private String virtualOrgId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基金会员
|
* 基金会员
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ public interface SysFileService extends BaseService<Sys_file> {
|
|||||||
*/
|
*/
|
||||||
String uploadReturnUrl(String engine, TempFile file);
|
String uploadReturnUrl(String engine, TempFile file);
|
||||||
|
|
||||||
String uploadReturnUrl(String engine, String fileName, byte[] bytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页
|
* 分页
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ import org.nutz.mvc.upload.TempFile;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -43,6 +47,9 @@ import java.nio.file.StandardOpenOption;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -54,6 +61,9 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
static String IMG_BASE64_PATTERN = "<img\\s+[^>]*src\\s*=\\s*['\"](data:image/[^'\"]+;base64,[^'\"]+)['\"][^>]*>";
|
static String IMG_BASE64_PATTERN = "<img\\s+[^>]*src\\s*=\\s*['\"](data:image/[^'\"]+;base64,[^'\"]+)['\"][^>]*>";
|
||||||
private static final int DOWNLOAD_FILE_CACHE_LIMIT = 2000;
|
private static final int DOWNLOAD_FILE_CACHE_LIMIT = 2000;
|
||||||
private final Map<String, Sys_file> downloadFileCache = new ConcurrentHashMap<>();
|
private final Map<String, Sys_file> downloadFileCache = new ConcurrentHashMap<>();
|
||||||
|
private static final Set<String> UPLOAD_SUFFIXES = Set.of("gif", "jpg", "jpeg", "png", "doc", "docx",
|
||||||
|
"xls", "xlsx", "rar", "zip", "7z", "txt", "pdf", "pptx", "ppt", "mp4");
|
||||||
|
private static final Set<String> ACTIVE_SUFFIXES = Set.of("svg", "svgz", "html", "htm", "xhtml", "xml", "js", "mjs", "swf");
|
||||||
|
|
||||||
public SysFileServiceImpl(Dao dao) {
|
public SysFileServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
@@ -69,11 +79,6 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
return this.storageFile(engine, file, false);
|
return this.storageFile(engine, file, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String uploadReturnUrl(String engine, String fileName, byte[] bytes) {
|
|
||||||
return this.storageFile(engine, fileName, bytes, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pagination page(Sys_file file) {
|
public Pagination page(Sys_file file) {
|
||||||
return null;
|
return null;
|
||||||
@@ -86,11 +91,13 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void download(String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
public void download(String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
if (handleCachedFileRequest(id, request, response)) {
|
response.setHeader("X-Content-Type-Options", "nosniff");
|
||||||
return;
|
response.setHeader("Cache-Control", "private, no-store");
|
||||||
}
|
|
||||||
Sys_file sys_file = fetchDownloadFile(id);
|
Sys_file sys_file = fetchDownloadFile(id);
|
||||||
if (!ObjectUtil.isEmpty(sys_file) && handleCachedImageRequest(sys_file, request, response)) {
|
// 历史主动内容也必须在缓存协商前拦截,避免旧 SVG 继续在业务域下执行。
|
||||||
|
if (sys_file != null && (ACTIVE_SUFFIXES.contains(StrUtil.blankToDefault(sys_file.getSuffix(), "").toLowerCase(Locale.ROOT))
|
||||||
|
|| ACTIVE_SUFFIXES.contains(FileUtil.extName(sys_file.getName()).toLowerCase(Locale.ROOT)))) {
|
||||||
|
response.sendError(HttpServletResponse.SC_FORBIDDEN, "不允许访问此类型的附件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ObjectUtil.isEmpty(sys_file)) {
|
if (ObjectUtil.isEmpty(sys_file)) {
|
||||||
@@ -117,16 +124,6 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleCachedFileRequest(String id, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
String etag = buildFileEtag(id);
|
|
||||||
if (etag.equals(request.getHeader("If-None-Match"))) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
|
||||||
setImageCacheHeaders(response, etag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Sys_file fetchDownloadFile(String id) {
|
private Sys_file fetchDownloadFile(String id) {
|
||||||
if (StrUtil.isBlank(id)) {
|
if (StrUtil.isBlank(id)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -145,23 +142,15 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
return sysFile;
|
return sysFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleCachedImageRequest(Sys_file sysFile, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
if (!isImage(sysFile)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String etag = buildFileEtag(sysFile);
|
|
||||||
if (etag.equals(request.getHeader("If-None-Match"))) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
|
||||||
setImageCacheHeaders(response, etag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean writeImageResponse(Sys_file sysFile, byte[] bytes, HttpServletResponse response) throws IOException {
|
private boolean writeImageResponse(Sys_file sysFile, byte[] bytes, HttpServletResponse response) throws IOException {
|
||||||
if (!isImage(sysFile)) {
|
if (!isImage(sysFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
String suffix = StrUtil.blankToDefault(sysFile.getSuffix(), FileUtil.extName(sysFile.getName())).toLowerCase(Locale.ROOT);
|
||||||
|
if (!isValidImage(bytes, suffix)) {
|
||||||
|
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "图片内容与文件类型不符");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
setImageCacheHeaders(response, buildFileEtag(sysFile));
|
setImageCacheHeaders(response, buildFileEtag(sysFile));
|
||||||
response.setHeader("Content-Disposition", "inline;filename=" + java.net.URLEncoder.encode(sysFile.getName(), java.nio.charset.StandardCharsets.UTF_8));
|
response.setHeader("Content-Disposition", "inline;filename=" + java.net.URLEncoder.encode(sysFile.getName(), java.nio.charset.StandardCharsets.UTF_8));
|
||||||
response.setHeader("Content-Length", String.valueOf(bytes.length));
|
response.setHeader("Content-Length", String.valueOf(bytes.length));
|
||||||
@@ -171,9 +160,9 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setImageCacheHeaders(HttpServletResponse response, String etag) {
|
private void setImageCacheHeaders(HttpServletResponse response, String etag) {
|
||||||
response.setHeader("Cache-Control", "public, max-age=604800, immutable");
|
response.setHeader("Cache-Control", "private, no-cache");
|
||||||
response.setHeader("ETag", etag);
|
response.setHeader("ETag", etag);
|
||||||
response.setDateHeader("Expires", System.currentTimeMillis() + 604800000L);
|
response.setDateHeader("Expires", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildFileEtag(Sys_file sysFile) {
|
private String buildFileEtag(Sys_file sysFile) {
|
||||||
@@ -181,12 +170,12 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String buildFileEtag(String id) {
|
private String buildFileEtag(String id) {
|
||||||
return "\"" + id + "\"";
|
return "\"safe-" + id + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isImage(Sys_file sysFile) {
|
private boolean isImage(Sys_file sysFile) {
|
||||||
String suffix = StrUtil.blankToDefault(sysFile.getSuffix(), FileUtil.extName(sysFile.getName())).toLowerCase();
|
String suffix = StrUtil.blankToDefault(sysFile.getSuffix(), FileUtil.extName(sysFile.getName())).toLowerCase();
|
||||||
return "jpg".equals(suffix) || "jpeg".equals(suffix) || "png".equals(suffix) || "gif".equals(suffix) || "webp".equals(suffix) || "bmp".equals(suffix) || "svg".equals(suffix);
|
return "jpg".equals(suffix) || "jpeg".equals(suffix) || "png".equals(suffix) || "gif".equals(suffix) || "webp".equals(suffix) || "bmp".equals(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getImageContentType(Sys_file sysFile) {
|
private String getImageContentType(Sys_file sysFile) {
|
||||||
@@ -197,7 +186,6 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
case "gif" -> "image/gif";
|
case "gif" -> "image/gif";
|
||||||
case "webp" -> "image/webp";
|
case "webp" -> "image/webp";
|
||||||
case "bmp" -> "image/bmp";
|
case "bmp" -> "image/bmp";
|
||||||
case "svg" -> "image/svg+xml";
|
|
||||||
default -> "application/octet-stream";
|
default -> "application/octet-stream";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -310,6 +298,7 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
* 存储文件
|
* 存储文件
|
||||||
**/
|
**/
|
||||||
private String storageFile(String engine, TempFile file, boolean returnFileId) {
|
private String storageFile(String engine, TempFile file, boolean returnFileId) {
|
||||||
|
validateUpload(file);
|
||||||
// 如果引擎为空,默认使用本地
|
// 如果引擎为空,默认使用本地
|
||||||
if (ObjectUtil.isEmpty(engine)) {
|
if (ObjectUtil.isEmpty(engine)) {
|
||||||
engine = SysFileEngineTypeEnum.LOCAL.getValue();
|
engine = SysFileEngineTypeEnum.LOCAL.getValue();
|
||||||
@@ -383,6 +372,53 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 所有业务上传共用校验,客户端声明的 MIME 类型不能作为图片真实性依据。 */
|
||||||
|
private void validateUpload(TempFile file) {
|
||||||
|
if (file == null || StrUtil.isBlank(file.getSubmittedFileName())) {
|
||||||
|
throw new BaseException("请选择要上传的文件");
|
||||||
|
}
|
||||||
|
String suffix = FileUtil.extName(file.getSubmittedFileName()).toLowerCase(Locale.ROOT);
|
||||||
|
if (!UPLOAD_SUFFIXES.contains(suffix)) {
|
||||||
|
throw new BaseException("不允许上传此类型的文件");
|
||||||
|
}
|
||||||
|
if (Set.of("gif", "jpg", "jpeg", "png").contains(suffix)) {
|
||||||
|
try {
|
||||||
|
if (!isValidImage(Files.readAllBytes(file.getFile().toPath()), suffix)) {
|
||||||
|
throw new BaseException("图片内容与文件类型不符");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BaseException("图片读取失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 解码真实图片并限制像素数量,阻止伪装为图片的 SVG 和异常大尺寸图片。 */
|
||||||
|
private boolean isValidImage(byte[] bytes, String suffix) {
|
||||||
|
try (ImageInputStream input = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes))) {
|
||||||
|
if (input == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
if (!readers.hasNext()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ImageReader reader = readers.next();
|
||||||
|
try {
|
||||||
|
reader.setInput(input, true, true);
|
||||||
|
String expected = "jpg".equals(suffix) ? "jpeg" : suffix;
|
||||||
|
if (!expected.equalsIgnoreCase(reader.getFormatName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long pixels = (long) reader.getWidth(0) * reader.getHeight(0);
|
||||||
|
return pixels > 0 && pixels <= 40000000 && reader.read(0) != null;
|
||||||
|
} finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
} catch (IOException | RuntimeException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储文件
|
* 存储文件
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import cn.dev33.satoken.servlet.model.SaStorageForServlet;
|
|||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.mvc.Mvcs;
|
import org.nutz.mvc.Mvcs;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author wizzer@qq.com
|
* @author wizzer@qq.com
|
||||||
*/
|
*/
|
||||||
@@ -22,7 +25,20 @@ public class SaTokenContextImpl implements SaTokenContext {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SaResponse getResponse() {
|
public SaResponse getResponse() {
|
||||||
return new SaResponseForServlet(Mvcs.getResp());
|
// 当前 Sa-Token 版本没有 Cookie 安全属性配置,在写入登录 Cookie 时统一补齐。
|
||||||
|
return new SaResponseForServlet(new HttpServletResponseWrapper(Mvcs.getResp()) {
|
||||||
|
/**
|
||||||
|
* 限制登录 Cookie 的脚本访问,并在 HTTPS 请求中仅允许安全传输。
|
||||||
|
*
|
||||||
|
* @param cookie Sa-Token 写入或清除的 Cookie
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addCookie(Cookie cookie) {
|
||||||
|
cookie.setHttpOnly(true);
|
||||||
|
cookie.setSecure(cookie.getSecure() || Mvcs.getReq().isSecure());
|
||||||
|
super.addCookie(cookie);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.budwk.app.web.commons.ext.handler;
|
package com.budwk.app.web.commons.ext.handler;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.nutz.boot.starter.WebServletFace;
|
||||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.json.Json;
|
import org.nutz.json.Json;
|
||||||
import org.nutz.lang.util.NutMap;
|
import org.nutz.lang.util.NutMap;
|
||||||
@@ -9,28 +8,63 @@ import org.nutz.log.Log;
|
|||||||
import org.nutz.log.Logs;
|
import org.nutz.log.Logs;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
|
import javax.servlet.DispatcherType;
|
||||||
|
import javax.servlet.Servlet;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 错误页拦截器,登陆后台显示友好提示
|
* 错误页拦截器,登陆后台显示友好提示
|
||||||
*/
|
*/
|
||||||
@IocBean
|
@IocBean
|
||||||
public class WkErrorPageHandler extends ErrorPageErrorHandler {
|
public class WkErrorPageHandler extends HttpServlet implements WebServletFace {
|
||||||
private static final Log log = Logs.get();
|
private static final Log log = Logs.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回容器错误处理 Servlet 的注册名称。
|
||||||
|
* @return 独立于业务路由的 Servlet 名称
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public String getName() {
|
||||||
|
return "wkErrorPage";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回容器错误页的内部派发地址。
|
||||||
|
* @return 错误页映射路径
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getPathSpec() {
|
||||||
|
return "/__container_error";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前错误处理实例交给 NutzBoot 注册。
|
||||||
|
* @return 当前 Servlet 实例
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Servlet getServlet() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
if (request.getDispatcherType() != DispatcherType.ERROR) {
|
||||||
|
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (response.getStatus() == 403 || response.getStatus() == 404 || response.getStatus() == 500) {
|
if (response.getStatus() == 403 || response.getStatus() == 404 || response.getStatus() == 500) {
|
||||||
try {
|
try {
|
||||||
if (isAjax(request)) {
|
if (isAjax(request)) {
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
response.getWriter().write(Json.toJson(new NutMap("code", "-1").setv("msg", response.getStatus() + " error")));
|
response.getWriter().write(Json.toJson(new NutMap("code", "-1").setv("msg", response.getStatus() + " error")));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
request.setAttribute("original_request_uri", request.getRequestURI());
|
request.setAttribute("original_request_uri", request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI));
|
||||||
RequestDispatcher rd = request.getRequestDispatcher("/platform/home/" + response.getStatus());
|
RequestDispatcher rd = request.getRequestDispatcher("/platform/home/" + response.getStatus());
|
||||||
rd.forward(request, response);
|
rd.forward(request, response);
|
||||||
return;
|
return;
|
||||||
@@ -39,7 +73,7 @@ public class WkErrorPageHandler extends ErrorPageErrorHandler {
|
|||||||
log.error(e);
|
log.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.handle(target, baseRequest, request, response);
|
// 不回落到容器默认错误页,避免泄露异常堆栈和容器信息。
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAjax(ServletRequest req) {
|
private boolean isAjax(ServletRequest req) {
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.budwk.app.web.commons.ext.handler;
|
||||||
|
|
||||||
|
import com.budwk.app.web.commons.ext.websocket.WkWebSocket;
|
||||||
|
import org.apache.catalina.core.StandardContext;
|
||||||
|
import org.apache.catalina.Executor;
|
||||||
|
import org.apache.catalina.core.StandardThreadExecutor;
|
||||||
|
import org.apache.catalina.startup.Tomcat;
|
||||||
|
import org.apache.catalina.valves.ErrorReportValve;
|
||||||
|
import org.apache.tomcat.websocket.server.WsSci;
|
||||||
|
import org.apache.tomcat.util.descriptor.web.FilterMap;
|
||||||
|
import org.nutz.boot.NbApp;
|
||||||
|
import org.nutz.boot.starter.tomcat.TomcatStarter;
|
||||||
|
import org.nutz.boot.tools.NbAppEventListener;
|
||||||
|
import org.nutz.ioc.impl.PropertiesProxy;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在容器启动前补齐 NutzBoot Tomcat 的 WebSocket 注册和线程池绑定。
|
||||||
|
*/
|
||||||
|
public class WkTomcatConfiguration implements NbAppEventListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置官方嵌入式 Tomcat,保留项目的监听地址与消息推送能力。
|
||||||
|
*
|
||||||
|
* @param app 当前 NutzBoot 应用
|
||||||
|
* @param eventType 只在服务器启动前配置,避免重复注册端点
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void whenStartServers(NbApp app, EventType eventType) {
|
||||||
|
if (eventType != EventType.before) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TomcatStarter starter = app.getAppContext().getIoc().get(TomcatStarter.class);
|
||||||
|
Tomcat tomcat = starter.getServer();
|
||||||
|
PropertiesProxy conf = app.getAppContext().getConf();
|
||||||
|
tomcat.getConnector().setProperty("address", starter.getHost());
|
||||||
|
|
||||||
|
// Starter 创建了共享线程池,但尚未把它交给 Connector 使用。
|
||||||
|
for (Executor executor : tomcat.getService().findExecutors()) {
|
||||||
|
if (executor instanceof StandardThreadExecutor) {
|
||||||
|
StandardThreadExecutor threads = (StandardThreadExecutor) executor;
|
||||||
|
threads.setMinSpareThreads(conf.getInt("tomcat.executor.minSpareThreads", 10));
|
||||||
|
threads.setMaxIdleTime(conf.getInt("tomcat.executor.maxIdleTime", 60000));
|
||||||
|
tomcat.getConnector().getProtocolHandler().setExecutor(threads);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NutzBoot 使用编程式 Context,必须显式运行官方 WebSocket 初始化器。
|
||||||
|
StandardContext context = (StandardContext) tomcat.getHost().findChild(starter.getContextPath());
|
||||||
|
context.setUseHttpOnly(conf.getBoolean("tomcat.session.cookie.httponly", true));
|
||||||
|
context.addServletContainerInitializer(new WsSci(), Set.of(WkWebSocket.class));
|
||||||
|
// Tomcat 的错误页再次 forward 时仍保持 ERROR 派发;让 MVC 渲染原业务错误页。
|
||||||
|
// Nutz 的过滤器在前一个监听器中注册,须等其完成后才能添加映射。
|
||||||
|
context.addApplicationLifecycleListener(new ServletContextListener() {
|
||||||
|
/**
|
||||||
|
* 在 Nutz 注册完成后补充业务错误页的 ERROR 派发映射。
|
||||||
|
* @param event 当前 Servlet 上下文初始化事件
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent event) {
|
||||||
|
FilterMap errorPages = new FilterMap();
|
||||||
|
errorPages.setFilterName("nutz");
|
||||||
|
errorPages.setDispatcher("ERROR");
|
||||||
|
// ERROR 再转发时 URL 匹配路径不变,按目标 Servlet 匹配才能进入 MVC。
|
||||||
|
errorPages.addServletName("default");
|
||||||
|
context.addFilterMap(errorPages);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Host 的兜底错误页也不能重新暴露此前已关闭的版本和堆栈。
|
||||||
|
ErrorReportValve errorReport = null;
|
||||||
|
for (org.apache.catalina.Valve valve : tomcat.getHost().getPipeline().getValves()) {
|
||||||
|
if (valve instanceof ErrorReportValve) {
|
||||||
|
errorReport = (ErrorReportValve) valve;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errorReport == null) {
|
||||||
|
errorReport = new ErrorReportValve();
|
||||||
|
tomcat.getHost().getPipeline().addValve(errorReport);
|
||||||
|
}
|
||||||
|
errorReport.setShowReport(false);
|
||||||
|
errorReport.setShowServerInfo(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -54,7 +54,7 @@ import java.util.List;
|
|||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/unionReimburse/apply")
|
@At("/platform/unionReimburse/apply")
|
||||||
@Api("工会报销申请")
|
@Api("工会报销申请")
|
||||||
@Ok("json:full")
|
@Ok("json:{locked:'condolenceIdCard|condolenceBirthday|condolenceMobile',ignoreNull:false}")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UnionReimburseApplyController {
|
public class UnionReimburseApplyController {
|
||||||
|
|
||||||
@@ -151,14 +151,11 @@ public class UnionReimburseApplyController {
|
|||||||
username as userName,
|
username as userName,
|
||||||
loginname as loginName,
|
loginname as loginName,
|
||||||
sex,
|
sex,
|
||||||
mobile,
|
|
||||||
technicalTitle,
|
technicalTitle,
|
||||||
IFNULL(unitname, '暂无') as unitName,
|
IFNULL(unitname, '暂无') as unitName,
|
||||||
unitid as unitId,
|
unitid as unitId,
|
||||||
unionid as unionId,
|
unionid as unionId,
|
||||||
unionname as unionName,
|
unionname as unionName,
|
||||||
DATE(birthday) AS birthday,
|
|
||||||
idCard,
|
|
||||||
unionCode
|
unionCode
|
||||||
from
|
from
|
||||||
vw_user
|
vw_user
|
||||||
@@ -173,6 +170,9 @@ public class UnionReimburseApplyController {
|
|||||||
}
|
}
|
||||||
cnd.and(View_user::getId, "!=", SecurityUtil.getUserId());
|
cnd.and(View_user::getId, "!=", SecurityUtil.getUserId());
|
||||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||||
|
if (StrUtil.isBlank(SecurityUtil.getUnionId())) {
|
||||||
|
return Result.success(java.util.Collections.emptyList());
|
||||||
|
}
|
||||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||||
}
|
}
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/unionReimburse/certifierUserSign")
|
@At("/platform/unionReimburse/certifierUserSign")
|
||||||
@Ok("json:full")
|
@Ok("json:{locked:'condolenceIdCard|condolenceBirthday|condolenceMobile',ignoreNull:false}")
|
||||||
@Api("证明人签字")
|
@Api("证明人签字")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UnionReimburseCertifierUserSignController {
|
public class UnionReimburseCertifierUserSignController {
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@ import java.util.HashMap;
|
|||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/unionReimburse/mine")
|
@At("/platform/unionReimburse/mine")
|
||||||
@Api("工会报销我的")
|
@Api("工会报销我的")
|
||||||
@Ok("json:full")
|
@Ok("json:{locked:'condolenceIdCard|condolenceBirthday|condolenceMobile',ignoreNull:false}")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UnionReimburseMineController {
|
public class UnionReimburseMineController {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ import java.util.List;
|
|||||||
|
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/unionReimburse/review")
|
@At("/platform/unionReimburse/review")
|
||||||
@Ok("json:full")
|
@Ok("json:{locked:'condolenceIdCard|condolenceBirthday|condolenceMobile',ignoreNull:false}")
|
||||||
@Api("工会报销审核")
|
@Api("工会报销审核")
|
||||||
public class UnionReimburseReviewController {
|
public class UnionReimburseReviewController {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ import java.util.List;
|
|||||||
|
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/unionReimburse/statistics")
|
@At("/platform/unionReimburse/statistics")
|
||||||
@Ok("json:full")
|
@Ok("json:{locked:'condolenceIdCard|condolenceBirthday|condolenceMobile',ignoreNull:false}")
|
||||||
@Api("慰问统计")
|
@Api("慰问统计")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UnionReimburseStatisticsController {
|
public class UnionReimburseStatisticsController {
|
||||||
|
|||||||
+123
-3
@@ -4,10 +4,12 @@ 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.core.util.StrUtil;
|
||||||
import com.budwk.app.base.constant.RoleConstant;
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
|
import com.budwk.app.base.exception.BaseException;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.models.Sys_file;
|
import com.budwk.app.sys.models.Sys_file;
|
||||||
|
import com.budwk.app.sys.views.View_user;
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
import com.budwk.app.sys.services.SysFileService;
|
||||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
import com.budwk.app.zhgh.club.model.ClubUser;
|
||||||
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
|
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
|
||||||
@@ -125,6 +127,37 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (oldRecord == null) {
|
if (oldRecord == null) {
|
||||||
return Result.error("未找到对应的报销记录");
|
return Result.error("未找到对应的报销记录");
|
||||||
}
|
}
|
||||||
|
if (!isAdmin() && !Objects.equals(oldRecord.getUserId(), SecurityUtil.getUserId())) {
|
||||||
|
return Result.error("无权修改此报销申请");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 人员身份和敏感资料由服务端补齐,避免前端删减字段导致丢失或被篡改。
|
||||||
|
if (oldRecord == null) {
|
||||||
|
View_user handler = dao().fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
|
||||||
|
if (handler == null) {
|
||||||
|
return Result.error("经办人信息不存在");
|
||||||
|
}
|
||||||
|
unionReimburse.setUserId(handler.getId());
|
||||||
|
unionReimburse.setUserName(handler.getUsername());
|
||||||
|
unionReimburse.setLoginName(handler.getLoginname());
|
||||||
|
unionReimburse.setUnitId(handler.getUnitId());
|
||||||
|
unionReimburse.setUnitName(handler.getUnitName());
|
||||||
|
unionReimburse.setUnionId(handler.getUnionId());
|
||||||
|
unionReimburse.setUnionName(handler.getUnionName());
|
||||||
|
} else {
|
||||||
|
// 修改历史单据时保留原经办组织,避免人员调动改变经费归属。
|
||||||
|
unionReimburse.setUserId(oldRecord.getUserId());
|
||||||
|
unionReimburse.setUserName(oldRecord.getUserName());
|
||||||
|
unionReimburse.setLoginName(oldRecord.getLoginName());
|
||||||
|
unionReimburse.setUnitId(oldRecord.getUnitId());
|
||||||
|
unionReimburse.setUnitName(oldRecord.getUnitName());
|
||||||
|
unionReimburse.setUnionId(oldRecord.getUnionId());
|
||||||
|
unionReimburse.setUnionName(oldRecord.getUnionName());
|
||||||
|
}
|
||||||
|
Result recipientResult = fillCondolencePersonalData(unionReimburse, oldRecord);
|
||||||
|
if (recipientResult != null) {
|
||||||
|
return recipientResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizeInvoiceDetails(unionReimburse);
|
normalizeInvoiceDetails(unionReimburse);
|
||||||
@@ -179,14 +212,104 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (unionReimburse == null) {
|
if (unionReimburse == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!canReadApply(unionReimburse)) {
|
||||||
|
throw new BaseException("无权查看此报销申请");
|
||||||
|
}
|
||||||
List<UnionReimburseInvoiceDetail> invoiceDetails = this.dao().query(
|
List<UnionReimburseInvoiceDetail> invoiceDetails = this.dao().query(
|
||||||
UnionReimburseInvoiceDetail.class,
|
UnionReimburseInvoiceDetail.class,
|
||||||
Cnd.where("reimburseId", "=", id).asc("createdAt")
|
Cnd.where("reimburseId", "=", id).asc("createdAt")
|
||||||
);
|
);
|
||||||
unionReimburse.setInvoiceDetails(invoiceDetails == null ? new ArrayList<>() : invoiceDetails);
|
unionReimburse.setInvoiceDetails(invoiceDetails == null ? new ArrayList<>() : invoiceDetails);
|
||||||
|
// 申请页和详情页共用此接口,原始身份资料仅保留在服务端业务记录中。
|
||||||
|
unionReimburse.setCondolenceIdCard(null);
|
||||||
|
unionReimburse.setCondolenceBirthday(null);
|
||||||
|
unionReimburse.setCondolenceMobile(null);
|
||||||
return unionReimburse;
|
return unionReimburse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 保留历史单据的身份资料快照,新选人员须符合人员查询的数据范围。 */
|
||||||
|
private Result fillCondolencePersonalData(UnionReimburse form, UnionReimburse oldRecord) {
|
||||||
|
form.setCondolenceIdCard(null);
|
||||||
|
form.setCondolenceBirthday(null);
|
||||||
|
form.setCondolenceMobile(null);
|
||||||
|
if (!"UNION_REIMBURSE_PROJECT_1".equals(form.getReimburseProject())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(form.getCondolenceUserId())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (oldRecord != null && Objects.equals(oldRecord.getCondolenceUserId(), form.getCondolenceUserId())) {
|
||||||
|
form.setCondolenceIdCard(oldRecord.getCondolenceIdCard());
|
||||||
|
form.setCondolenceBirthday(oldRecord.getCondolenceBirthday());
|
||||||
|
form.setCondolenceMobile(oldRecord.getCondolenceMobile());
|
||||||
|
form.setCondolenceUnionId(oldRecord.getCondolenceUnionId());
|
||||||
|
form.setCondolenceUnitId(oldRecord.getCondolenceUnitId());
|
||||||
|
form.setCondolenceUserName(oldRecord.getCondolenceUserName());
|
||||||
|
form.setCondolenceLoginName(oldRecord.getCondolenceLoginName());
|
||||||
|
form.setCondolenceUnitName(oldRecord.getCondolenceUnitName());
|
||||||
|
form.setCondolenceUnionName(oldRecord.getCondolenceUnionName());
|
||||||
|
form.setCondolenceUnionCode(oldRecord.getCondolenceUnionCode());
|
||||||
|
form.setCondolenceSex(oldRecord.getCondolenceSex());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
View_user user = dao().fetch(View_user.class, Cnd.where("id", "=", form.getCondolenceUserId()));
|
||||||
|
if (user == null || Objects.equals(user.getId(), SecurityUtil.getUserId())
|
||||||
|
|| (!isAdmin() && (StrUtil.isBlank(SecurityUtil.getUnionId())
|
||||||
|
|| !Objects.equals(SecurityUtil.getUnionId(), user.getUnionId())))) {
|
||||||
|
return Result.error("无权选择此慰问对象");
|
||||||
|
}
|
||||||
|
form.setCondolenceUserName(user.getUsername());
|
||||||
|
form.setCondolenceLoginName(user.getLoginname());
|
||||||
|
form.setCondolenceUnitId(user.getUnitId());
|
||||||
|
form.setCondolenceUnitName(user.getUnitName());
|
||||||
|
form.setCondolenceUnionId(user.getUnionId());
|
||||||
|
form.setCondolenceUnionName(user.getUnionName());
|
||||||
|
form.setCondolenceUnionCode(user.getUnionCode());
|
||||||
|
form.setCondolenceSex(user.getSex());
|
||||||
|
form.setCondolenceIdCard(user.getIdCard());
|
||||||
|
form.setCondolenceBirthday(user.getBirthday() == null ? null : DateUtil.formatDate(user.getBirthday()));
|
||||||
|
form.setCondolenceMobile(user.getMobile());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 详情访问沿用经办、审核、统计和流程参与范围,不能仅凭单据 ID 查询。 */
|
||||||
|
private boolean canReadApply(UnionReimburse form) {
|
||||||
|
String userId = SecurityUtil.getUserId();
|
||||||
|
if (StrUtil.isBlank(userId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isAdmin() || userId.equals(form.getUserId())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (form.getStateId() != 1 && (AuthUtil.hasPermission("unionReimburse.review")
|
||||||
|
|| AuthUtil.hasPermission("h5.unionReimburse.review"))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((form.getStateId() == 2 || form.getStateId() == 3)
|
||||||
|
&& StrUtil.isNotBlank(SecurityUtil.getUnionId())
|
||||||
|
&& Objects.equals(SecurityUtil.getUnionId(), form.getCondolenceUnionId())
|
||||||
|
&& (AuthUtil.hasPermission("unionReimburse.statistics")
|
||||||
|
|| AuthUtil.hasPermission("h5.unionReimburse.statistics"))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 旧流程单据允许任务参与人和抄送人回看,关系必须由数据库确认。
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT COUNT(*) FROM wf_process_instance i
|
||||||
|
WHERE i.businessNo = @id AND (
|
||||||
|
EXISTS (SELECT 1 FROM wf_process_task t
|
||||||
|
INNER JOIN wf_process_task_actor a ON a.processTaskId = t.id
|
||||||
|
WHERE t.processInstanceId = i.id AND a.actorId = @userId)
|
||||||
|
OR EXISTS (SELECT 1 FROM wf_process_cc_instance c
|
||||||
|
WHERE c.processInstanceId = i.id AND c.actorId = @userId)
|
||||||
|
)
|
||||||
|
""");
|
||||||
|
sql.setParam("id", form.getId());
|
||||||
|
sql.setParam("userId", userId);
|
||||||
|
sql.setCallback(Sqls.callback.integer());
|
||||||
|
dao().execute(sql);
|
||||||
|
return sql.getInt() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteApply(String id) {
|
public void deleteApply(String id) {
|
||||||
if (StrUtil.isBlank(id)) {
|
if (StrUtil.isBlank(id)) {
|
||||||
@@ -242,14 +365,11 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
u.username AS userName,
|
u.username AS userName,
|
||||||
u.loginname AS loginName,
|
u.loginname AS loginName,
|
||||||
u.sex,
|
u.sex,
|
||||||
u.mobile,
|
|
||||||
u.technicalTitle,
|
u.technicalTitle,
|
||||||
IFNULL(u.unitname, '暂无') AS unitName,
|
IFNULL(u.unitname, '暂无') AS unitName,
|
||||||
u.unitid AS unitId,
|
u.unitid AS unitId,
|
||||||
u.unionid AS unionId,
|
u.unionid AS unionId,
|
||||||
u.unionname AS unionName,
|
u.unionname AS unionName,
|
||||||
DATE(u.birthday) AS birthday,
|
|
||||||
u.idCard,
|
|
||||||
u.unionCode
|
u.unionCode
|
||||||
FROM
|
FROM
|
||||||
vw_user u
|
vw_user u
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
|
||||||
import org.nutz.dao.entity.annotation.*;
|
import org.nutz.dao.entity.annotation.*;
|
||||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||||
|
|
||||||
@@ -161,13 +160,13 @@ public class MallGoods extends BaseModel {
|
|||||||
//循环sku,判定sku是否有效
|
//循环sku,判定sku是否有效
|
||||||
for (Map<String, Object> sku : goodsOperationDTO.getSkuList()) {
|
for (Map<String, Object> sku : goodsOperationDTO.getSkuList()) {
|
||||||
//判定参数不能为空
|
//判定参数不能为空
|
||||||
if ((!sku.containsKey("price") || StringUtil.isEmpty(sku.get("price").toString()) || Convert.toDouble(sku.get("price")) <= 0)) {
|
if ((!sku.containsKey("price") || CharSequenceUtil.isEmpty(sku.get("price").toString()) || Convert.toDouble(sku.get("price")) <= 0)) {
|
||||||
throw new BaseException("商品SKU价格不能小于等于0");
|
throw new BaseException("商品SKU价格不能小于等于0");
|
||||||
}
|
}
|
||||||
// if ((!sku.containsKey("cost") || StringUtil.isEmpty(sku.get("cost").toString()) || Convert.toDouble(sku.get("cost")) <= 0)) {
|
// if ((!sku.containsKey("cost") || StringUtil.isEmpty(sku.get("cost").toString()) || Convert.toDouble(sku.get("cost")) <= 0)) {
|
||||||
// throw new BaseException("商品SKU成本价不能小于等于0");
|
// throw new BaseException("商品SKU成本价不能小于等于0");
|
||||||
// }
|
// }
|
||||||
if (!sku.containsKey("quantity") || StringUtil.isEmpty(sku.get("quantity").toString()) || Convert.toInt(sku.get("quantity").toString()) < 0) {
|
if (!sku.containsKey("quantity") || CharSequenceUtil.isEmpty(sku.get("quantity").toString()) || Convert.toInt(sku.get("quantity").toString()) < 0) {
|
||||||
throw new BaseException("商品库存数量不能为负数");
|
throw new BaseException("商品库存数量不能为负数");
|
||||||
}
|
}
|
||||||
sku.values().forEach(i -> {
|
sku.values().forEach(i -> {
|
||||||
|
|||||||
-21
@@ -37,34 +37,13 @@ public class PointsMallInvoiceController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("points.mall.invoice")
|
@SaCheckPermission("points.mall.invoice")
|
||||||
public Result infoPage(PointsMallInvoiceInfoPageParam param) {
|
public Result infoPage(PointsMallInvoiceInfoPageParam param) {
|
||||||
try {
|
|
||||||
return Result.success(pointsMallInvoiceService.infoPage(param));
|
return Result.success(pointsMallInvoiceService.infoPage(param));
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return Result.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("points.mall.invoice")
|
@SaCheckPermission("points.mall.invoice")
|
||||||
public Result infoDetail(@Param("id") String id) {
|
public Result infoDetail(@Param("id") String id) {
|
||||||
try {
|
|
||||||
return Result.success(pointsMallInvoiceService.infoDetail(id));
|
return Result.success(pointsMallInvoiceService.infoDetail(id));
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return Result.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@At
|
|
||||||
@org.nutz.mvc.annotation.POST
|
|
||||||
@SLog(tag = "积分商城发票管理", msg = "重新获取发票")
|
|
||||||
@SaCheckPermission("points.mall.invoice")
|
|
||||||
public Result retryInvoice(@Param("mainId") String mainId) {
|
|
||||||
try {
|
|
||||||
pointsMallInvoiceService.retryInvoice(mainId);
|
|
||||||
return Result.success();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return Result.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ import java.util.Date;
|
|||||||
@Comment("积分商城发票信息")
|
@Comment("积分商城发票信息")
|
||||||
public class PointsMallInvoiceInfo extends BaseModel implements Serializable {
|
public class PointsMallInvoiceInfo extends BaseModel implements Serializable {
|
||||||
|
|
||||||
// 详情实时读取供应商 PDF 生成结果:1 成功,2 失败,不以本地文件地址推断状态。
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Name
|
@Name
|
||||||
@Column
|
@Column
|
||||||
@Comment("ID")
|
@Comment("ID")
|
||||||
|
|||||||
+1
-3
@@ -7,13 +7,11 @@ public class PointsMallInvoiceApplyParam {
|
|||||||
|
|
||||||
private String supplierId;
|
private String supplierId;
|
||||||
private String orderIds;
|
private String orderIds;
|
||||||
private String queryOrderId;
|
|
||||||
private String userId;
|
|
||||||
private String startDate;
|
private String startDate;
|
||||||
private String endDate;
|
private String endDate;
|
||||||
private String invoiceDate;
|
private String invoiceDate;
|
||||||
private String invoiceTitle;
|
private String invoiceTitle;
|
||||||
private String taxIdNumber;
|
private String invoiceCode;
|
||||||
private String invoiceAddress;
|
private String invoiceAddress;
|
||||||
private String invoiceContact;
|
private String invoiceContact;
|
||||||
private Integer invoiceType;
|
private Integer invoiceType;
|
||||||
|
|||||||
+1
-12
@@ -3,9 +3,6 @@ package com.budwk.app.zhgh.pointsmall.invoice.service;
|
|||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.service.BaseService;
|
import com.budwk.app.base.service.BaseService;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceApplyParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceApplyParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceInfoPageParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceInfoPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceMainPageParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceMainPageParam;
|
||||||
@@ -18,19 +15,11 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface PointsMallInvoiceService extends BaseService<PointsMallInvoiceMain> {
|
public interface PointsMallInvoiceService extends BaseService<PointsMallInvoiceMain> {
|
||||||
|
|
||||||
/** 同步供应商发票信息及本地文件。 */
|
|
||||||
MallInboundResult invoiceInfo(MallOrderEventDTO dto);
|
|
||||||
|
|
||||||
/** 同步发票,可指定是否重新生成失败发票。 */
|
|
||||||
MallInboundResult invoiceInfo(MallOrderEventDTO dto, boolean retry);
|
|
||||||
|
|
||||||
Pagination<PointsMallInvoiceMain> mainPage(PointsMallInvoiceMainPageParam param);
|
Pagination<PointsMallInvoiceMain> mainPage(PointsMallInvoiceMainPageParam param);
|
||||||
|
|
||||||
Pagination<Record> infoPage(PointsMallInvoiceInfoPageParam param);
|
Pagination<Record> infoPage(PointsMallInvoiceInfoPageParam param);
|
||||||
|
|
||||||
PointsMallInvoiceInfo infoDetail(String id);
|
Record infoDetail(String id);
|
||||||
|
|
||||||
void retryInvoice(String mainId);
|
|
||||||
|
|
||||||
Pagination<Record> orderPage(PointsMallInvoiceOrderPageParam param);
|
Pagination<Record> orderPage(PointsMallInvoiceOrderPageParam param);
|
||||||
|
|
||||||
|
|||||||
+36
-319
@@ -6,207 +6,39 @@ import cn.hutool.core.util.RandomUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceApplyParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceApplyParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceInfoPageParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceInfoPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceMainPageParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceMainPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceOrderPageParam;
|
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceOrderPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.service.PointsMallInvoiceService;
|
import com.budwk.app.zhgh.pointsmall.invoice.service.PointsMallInvoiceService;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallInvoiceApplyDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.InvoiceInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.GetInvoiceInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInvoiceApplyOutboundService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInvoiceInfoQueryService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
||||||
import org.nutz.dao.Chain;
|
import org.nutz.dao.Chain;
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.entity.Record;
|
import org.nutz.dao.entity.Record;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
|
||||||
import com.budwk.app.sys.enums.SysFileEngineTypeEnum;
|
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvoiceMain> implements PointsMallInvoiceService {
|
public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvoiceMain> implements PointsMallInvoiceService {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MallInvoiceApplyOutboundService mallInvoiceApplyOutboundService;
|
|
||||||
@Inject
|
|
||||||
private SysFileService sysFileService;
|
|
||||||
@Inject
|
|
||||||
private MallInvoiceInfoQueryService mallInvoiceInfoQueryService;
|
|
||||||
|
|
||||||
public PointsMallInvoiceServiceImpl(Dao dao) {
|
public PointsMallInvoiceServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理供应商发票信息通知,查询发票并同步文件和开票结果。 */
|
|
||||||
@Override
|
|
||||||
public MallInboundResult invoiceInfo(MallOrderEventDTO dto) {
|
|
||||||
return invoiceInfo(dto, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** retry=true 时允许供应商重新生成失败发票,后续复用相同的同步流程。 */
|
|
||||||
@Override
|
|
||||||
public MallInboundResult invoiceInfo(MallOrderEventDTO dto, boolean retry) {
|
|
||||||
String settlementId = dto.getOrderId();
|
|
||||||
if (StrUtil.hasBlank(dto.getSupplierId(), settlementId)) {
|
|
||||||
return MallInboundResult.fail(400, "供应商和结算单号不能为空");
|
|
||||||
}
|
|
||||||
QueryInvoiceInfoDTO query = new QueryInvoiceInfoDTO();
|
|
||||||
query.setSupplierId(dto.getSupplierId());
|
|
||||||
query.setSettlementId(settlementId);
|
|
||||||
query.setRetry(retry);
|
|
||||||
GetInvoiceInfoDTO result;
|
|
||||||
try {
|
|
||||||
result = mallInvoiceInfoQueryService.queryInvoicesInfo(query);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("调用供应商获取发票信息失败,supplierId={},settlementId={}", dto.getSupplierId(), settlementId, e);
|
|
||||||
return MallInboundResult.fail(-1, "获取供应商发票信息失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
PointsMallInvoiceMain main = dao().fetch(PointsMallInvoiceMain.class,
|
|
||||||
Cnd.where("settlementId", "=", settlementId).and("delFlag", "=", false));
|
|
||||||
if (main == null) {
|
|
||||||
return MallInboundResult.fail(404, "开票申请记录不存在");
|
|
||||||
}
|
|
||||||
if (result == null || !settlementId.equals(result.getSettlementId())) {
|
|
||||||
return MallInboundResult.fail(502, "供应商返回的发票结算单不匹配");
|
|
||||||
}
|
|
||||||
Integer success = result.getBSuccess() == null ? 0 : result.getBSuccess();
|
|
||||||
if (success == 0) {
|
|
||||||
if (result.getInvoiceInfos() == null || result.getInvoiceInfos().isEmpty() || StrUtil.isBlank(result.getSucOrderIds())) {
|
|
||||||
return MallInboundResult.fail(502, "供应商开票结果缺少发票明细或成功订单");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
List<String> fileIds = result.getInvoiceInfos().stream().map(InvoiceInfoDTO::getInvoiceId).collect(Collectors.toList());
|
|
||||||
if (fileIds.stream().anyMatch(StrUtil::isBlank)) {
|
|
||||||
throw new IllegalArgumentException("供应商发票文件标识为空");
|
|
||||||
}
|
|
||||||
MallPictureOutboundResult files = mallInvoiceInfoQueryService.queryInvoiceFiles(dto.getSupplierId(), settlementId, fileIds);
|
|
||||||
for (InvoiceInfoDTO item : result.getInvoiceInfos()) {
|
|
||||||
if (item.getStatus() != null && item.getStatus() != 1) {
|
|
||||||
throw new IllegalArgumentException("供应商发票尚未生成成功");
|
|
||||||
}
|
|
||||||
String base64 = files.getImageEncodeMap() == null ? null : files.getImageEncodeMap().get(item.getInvoiceId());
|
|
||||||
if (StrUtil.isBlank(base64)) {
|
|
||||||
throw new IllegalArgumentException("未获取到发票文件Base64:" + item.getInvoiceId());
|
|
||||||
}
|
|
||||||
if (base64.startsWith("data:")) {
|
|
||||||
base64 = base64.substring(base64.indexOf(',') + 1);
|
|
||||||
}
|
|
||||||
byte[] bytes = Base64.getDecoder().decode(base64.replaceAll("\\s", ""));
|
|
||||||
if (bytes.length == 0) {
|
|
||||||
throw new IllegalArgumentException("发票文件内容为空");
|
|
||||||
}
|
|
||||||
String fileType = StrUtil.blankToDefault(files.getFileType(), StrUtil.blankToDefault(item.getFileType(), "PDF"));
|
|
||||||
if (!fileType.matches("(?i)pdf|jpg|jpeg|png")) {
|
|
||||||
throw new IllegalArgumentException("不支持的发票文件类型:" + fileType);
|
|
||||||
}
|
|
||||||
String localUrl = sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(),
|
|
||||||
"invoice-" + java.util.UUID.randomUUID() + "." + fileType.toLowerCase(java.util.Locale.ROOT), bytes);
|
|
||||||
item.setUrl(localUrl);
|
|
||||||
item.setImageEncode(localUrl);
|
|
||||||
item.setFileType(fileType);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("发票文件同步失败,settlementId={}", settlementId, e);
|
|
||||||
return MallInboundResult.fail(502, "发票文件同步失败:" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
main.setBSuccess(success);
|
|
||||||
main.setSucOrderIds(result.getSucOrderIds());
|
|
||||||
main.setFailOrderIds(result.getFailOrderIds());
|
|
||||||
main.setFailMsg(result.getFailMsg());
|
|
||||||
if (result.getInvoiceInfos() != null) {
|
|
||||||
for (InvoiceInfoDTO item : result.getInvoiceInfos()) {
|
|
||||||
PointsMallInvoiceInfo info = dao().fetch(PointsMallInvoiceInfo.class,
|
|
||||||
Cnd.where("mainId", "=", main.getId()).and("invoiceId", "=", item.getInvoiceId()).and("delFlag", "=", false));
|
|
||||||
if (info == null) {
|
|
||||||
info = new PointsMallInvoiceInfo();
|
|
||||||
info.setMainId(main.getId());
|
|
||||||
info.setInvoiceId(item.getInvoiceId());
|
|
||||||
}
|
|
||||||
info.setInvoiceCode(item.getInvoiceCode());
|
|
||||||
info.setInvoiceDate(item.getInvoiceDate() == null ? null : DateUtil.parse(item.getInvoiceDate().toString()));
|
|
||||||
info.setInvoiceNakeAmount(item.getInvoiceNakeAmount());
|
|
||||||
info.setInvoiceTaxRate(item.getInvoiceTaxRate());
|
|
||||||
info.setInvoiceTaxAmount(item.getInvoiceTaxAmount());
|
|
||||||
info.setInvoiceAmount(item.getInvoiceAmount());
|
|
||||||
info.setInvoiceType(item.getInvoiceType());
|
|
||||||
info.setUrl(item.getUrl());
|
|
||||||
info.setImageEncode(item.getImageEncode());
|
|
||||||
info.setFileType(item.getFileType());
|
|
||||||
info.setCheckCode(item.getCheckCode());
|
|
||||||
info.setInvoiceAddress(item.getInvoiceAddress());
|
|
||||||
info.setRemark(item.getRemark());
|
|
||||||
if (success != 0) {
|
|
||||||
info.setUrl("");
|
|
||||||
info.setImageEncode("");
|
|
||||||
}
|
|
||||||
if (StrUtil.isBlank(info.getId())) {
|
|
||||||
dao().insert(info);
|
|
||||||
} else {
|
|
||||||
dao().updateIgnoreNull(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> successOrderIds = splitInvoiceOrderIds(result.getSucOrderIds());
|
|
||||||
List<String> failOrderIds = splitInvoiceOrderIds(result.getFailOrderIds());
|
|
||||||
if (!successOrderIds.isEmpty()) {
|
|
||||||
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "in", successOrderIds).and("delFlag", "=", false));
|
|
||||||
}
|
|
||||||
if (!failOrderIds.isEmpty()) {
|
|
||||||
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 0), Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "in", failOrderIds).and("delFlag", "=", false));
|
|
||||||
}
|
|
||||||
dao().updateIgnoreNull(main);
|
|
||||||
});
|
|
||||||
log.info("供应商发票信息更新完成,supplierId={},settlementId={}", dto.getSupplierId(), settlementId);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 拆分开票结果中的订单号,去除空项和重复项,保留原有顺序。 */
|
|
||||||
private List<String> splitInvoiceOrderIds(String value) {
|
|
||||||
if (StrUtil.isBlank(value)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return Arrays.stream(value.split(","))
|
|
||||||
.map(String::trim)
|
|
||||||
.filter(StrUtil::isNotBlank)
|
|
||||||
.distinct()
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pagination<PointsMallInvoiceMain> mainPage(PointsMallInvoiceMainPageParam param) {
|
public Pagination<PointsMallInvoiceMain> mainPage(PointsMallInvoiceMainPageParam param) {
|
||||||
Cnd cnd = Cnd.where("delFlag", "=", false);
|
Cnd cnd = Cnd.where("delFlag", "=", false);
|
||||||
if (StrUtil.isNotBlank(param.getSettlementId())) {
|
if (StrUtil.isNotBlank(param.getSettlementId())) {
|
||||||
cnd.and("settlementId", "=", param.getSettlementId());
|
cnd.and("settlementId", "like", "%" + param.getSettlementId() + "%");
|
||||||
}
|
}
|
||||||
if (param.getBSuccess() != null) {
|
if (param.getBSuccess() != null) {
|
||||||
cnd.and("bSuccess", "=", param.getBSuccess());
|
cnd.and("bSuccess", "=", param.getBSuccess());
|
||||||
@@ -226,32 +58,15 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pagination<Record> infoPage(PointsMallInvoiceInfoPageParam param) {
|
public Pagination<Record> infoPage(PointsMallInvoiceInfoPageParam param) {
|
||||||
if (StrUtil.isNotBlank(param.getMainId()) && dao().count(PointsMallInvoiceInfo.class,
|
|
||||||
Cnd.where("mainId", "=", param.getMainId()).and("delFlag", "=", false)) == 0) {
|
|
||||||
PointsMallInvoiceMain main = fetch(param.getMainId());
|
|
||||||
PointsMallOrderSub order = main == null ? null : dao().fetch(PointsMallOrderSub.class,
|
|
||||||
Cnd.where("invoiceCode", "=", main.getSettlementId()).and("delFlag", "=", false));
|
|
||||||
if (order != null) {
|
|
||||||
MallOrderEventDTO event = new MallOrderEventDTO();
|
|
||||||
event.setSupplierId(order.getSupplierId());
|
|
||||||
event.setOrderId(main.getSettlementId());
|
|
||||||
MallInboundResult result = invoiceInfo(event);
|
|
||||||
if (result.getResultCode() != 0) {
|
|
||||||
dao().update(PointsMallInvoiceMain.class, Chain.make("bSuccess", 1).add("failMsg", result.getMessage()),
|
|
||||||
Cnd.where("id", "=", main.getId()));
|
|
||||||
throw new IllegalArgumentException(result.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Cnd cnd = Cnd.where("delFlag", "=", false);
|
Cnd cnd = Cnd.where("delFlag", "=", false);
|
||||||
if (StrUtil.isNotBlank(param.getMainId())) {
|
if (StrUtil.isNotBlank(param.getMainId())) {
|
||||||
cnd.and("mainId", "=", param.getMainId());
|
cnd.and("mainId", "=", param.getMainId());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getInvoiceId())) {
|
if (StrUtil.isNotBlank(param.getInvoiceId())) {
|
||||||
cnd.and("invoiceId", "=", param.getInvoiceId());
|
cnd.and("invoiceId", "like", "%" + param.getInvoiceId() + "%");
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getInvoiceCode())) {
|
if (StrUtil.isNotBlank(param.getInvoiceCode())) {
|
||||||
cnd.and("invoiceCode", "=", param.getInvoiceCode());
|
cnd.and("invoiceCode", "like", "%" + param.getInvoiceCode() + "%");
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getInvoiceDate())) {
|
if (StrUtil.isNotBlank(param.getInvoiceDate())) {
|
||||||
cnd.and("invoiceDate", "=", DateUtil.parse(param.getInvoiceDate()));
|
cnd.and("invoiceDate", "=", DateUtil.parse(param.getInvoiceDate()));
|
||||||
@@ -266,61 +81,13 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PointsMallInvoiceInfo infoDetail(String id) {
|
public Record infoDetail(String id) {
|
||||||
if (StrUtil.isBlank(id)) {
|
if (StrUtil.isBlank(id)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PointsMallInvoiceInfo info = dao().fetch(PointsMallInvoiceInfo.class, Cnd.where("id", "=", id).and("delFlag", "=", false));
|
Sql sql = Sqls.create("select * from points_mall_invoice_info where id=@id and delFlag=0");
|
||||||
if (info == null) {
|
sql.params().set("id", id);
|
||||||
return null;
|
return (Record) dao().execute(sql.setCallback(Sqls.callback.record())).getResult();
|
||||||
}
|
|
||||||
MallOrderEventDTO event = invoiceEvent(info.getMainId());
|
|
||||||
QueryInvoiceInfoDTO query = new QueryInvoiceInfoDTO();
|
|
||||||
query.setSupplierId(event.getSupplierId());
|
|
||||||
query.setSettlementId(event.getOrderId());
|
|
||||||
GetInvoiceInfoDTO result = mallInvoiceInfoQueryService.queryInvoicesInfo(query);
|
|
||||||
if (result == null || !event.getOrderId().equals(result.getSettlementId()) || result.getInvoiceInfos() == null) {
|
|
||||||
throw new IllegalArgumentException("供应商未返回对应结算单的发票详情");
|
|
||||||
}
|
|
||||||
InvoiceInfoDTO remote = result.getInvoiceInfos().stream()
|
|
||||||
.filter(item -> info.getInvoiceId().equals(item.getInvoiceId())).findFirst()
|
|
||||||
.orElseThrow(() -> new IllegalArgumentException("供应商未返回对应发票详情"));
|
|
||||||
info.setStatus(remote.getStatus());
|
|
||||||
info.setRemark(remote.getRemark());
|
|
||||||
if (!Integer.valueOf(1).equals(remote.getStatus())) {
|
|
||||||
info.setUrl("");
|
|
||||||
info.setImageEncode("");
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MallOrderEventDTO invoiceEvent(String mainId) {
|
|
||||||
PointsMallInvoiceMain main = StrUtil.isBlank(mainId) ? null : dao().fetch(PointsMallInvoiceMain.class,
|
|
||||||
Cnd.where("id", "=", mainId).and("delFlag", "=", false));
|
|
||||||
if (main == null) {
|
|
||||||
throw new IllegalArgumentException("开票申请记录不存在");
|
|
||||||
}
|
|
||||||
PointsMallOrderSub order = dao().fetch(PointsMallOrderSub.class,
|
|
||||||
Cnd.where("invoiceCode", "=", main.getSettlementId()).and("delFlag", "=", false));
|
|
||||||
if (order == null) {
|
|
||||||
throw new IllegalArgumentException("未找到结算单对应的供应商订单");
|
|
||||||
}
|
|
||||||
MallOrderEventDTO event = new MallOrderEventDTO();
|
|
||||||
event.setSupplierId(order.getSupplierId());
|
|
||||||
event.setOrderId(main.getSettlementId());
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void retryInvoice(String mainId) {
|
|
||||||
MallInboundResult result = invoiceInfo(invoiceEvent(mainId), true);
|
|
||||||
if (result.getResultCode() != 0) {
|
|
||||||
throw new IllegalArgumentException(result.getMessage());
|
|
||||||
}
|
|
||||||
PointsMallInvoiceMain main = fetch(mainId);
|
|
||||||
if (!Integer.valueOf(0).equals(main.getBSuccess())) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.blankToDefault(main.getFailMsg(), "供应商发票生成失败"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -350,19 +117,7 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
query.setEndDate(param.getEndDate());
|
query.setEndDate(param.getEndDate());
|
||||||
query.setInvoiceStatus(0);
|
query.setInvoiceStatus(0);
|
||||||
|
|
||||||
Cnd cnd = invoiceOrderCnd(query, "");
|
List<PointsMallOrderSub> orders = dao().query(PointsMallOrderSub.class, invoiceOrderCnd(query, ""));
|
||||||
if (StrUtil.isNotBlank(param.getQueryOrderId())) {
|
|
||||||
List<String> queryOrderIds = StrUtil.splitTrim(param.getQueryOrderId(), ",");
|
|
||||||
if (queryOrderIds.size() > 1) {
|
|
||||||
cnd.and("orderId", "in", queryOrderIds);
|
|
||||||
} else {
|
|
||||||
cnd.and("orderId", "like", "%" + param.getQueryOrderId() + "%");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(param.getUserId())) {
|
|
||||||
cnd.and("userId", "like", "%" + param.getUserId() + "%");
|
|
||||||
}
|
|
||||||
List<PointsMallOrderSub> orders = dao().query(PointsMallOrderSub.class, cnd);
|
|
||||||
if (CollUtil.isEmpty(orders)) {
|
if (CollUtil.isEmpty(orders)) {
|
||||||
throw new IllegalArgumentException("无符合条件的订单数据");
|
throw new IllegalArgumentException("无符合条件的订单数据");
|
||||||
}
|
}
|
||||||
@@ -371,69 +126,30 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
String settlementId = System.currentTimeMillis() + RandomUtil.randomNumbers(6);
|
String settlementId = System.currentTimeMillis() + RandomUtil.randomNumbers(6);
|
||||||
PointsMallInvoiceMain invoice = new PointsMallInvoiceMain();
|
PointsMallInvoiceMain invoice = new PointsMallInvoiceMain();
|
||||||
invoice.setSettlementId(settlementId);
|
invoice.setSettlementId(settlementId);
|
||||||
invoice.setBSuccess(null);
|
invoice.setBSuccess(0);
|
||||||
invoice.setSucOrderIds("");
|
invoice.setSucOrderIds(String.join(",", orderIds));
|
||||||
invoice.setFailOrderIds("");
|
invoice.setFailOrderIds("");
|
||||||
invoice.setFailMsg("");
|
invoice.setFailMsg("");
|
||||||
insert(invoice);
|
insert(invoice);
|
||||||
|
|
||||||
MallInvoiceApplyDTO dto = new MallInvoiceApplyDTO();
|
PointsMallInvoiceInfo info = new PointsMallInvoiceInfo();
|
||||||
dto.setSupplierId(param.getSupplierId());
|
info.setMainId(invoice.getId());
|
||||||
dto.setSettlementId(settlementId);
|
info.setInvoiceId(settlementId);
|
||||||
dto.setOrderIds(String.join(",", orderIds));
|
info.setInvoiceCode(param.getInvoiceCode());
|
||||||
dto.setOrderNum(orders.size());
|
info.setInvoiceDate(DateUtil.parse(param.getInvoiceDate()));
|
||||||
dto.setOrderTotalPrice(orders.stream().map(PointsMallOrderSub::getTotalPrice)
|
info.setInvoiceType(param.getInvoiceType());
|
||||||
.filter(java.util.Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
|
info.setInvoiceAmount(orderTotalPoints(query));
|
||||||
dto.setInvoiceDate(param.getInvoiceDate());
|
info.setInvoiceNakeAmount(info.getInvoiceAmount());
|
||||||
dto.setInvoiceTitle(param.getInvoiceTitle());
|
info.setInvoiceAddress(param.getInvoiceAddress());
|
||||||
dto.setTaxIdNumber(param.getTaxIdNumber());
|
info.setInvoiceContact(param.getInvoiceContact());
|
||||||
dto.setInvoiceAddress(param.getInvoiceAddress());
|
info.setInvoiceContent(param.getInvoiceContent());
|
||||||
dto.setInvoiceContact(param.getInvoiceContact());
|
info.setTaxIdNumber(param.getInvoiceCode());
|
||||||
dto.setInvoiceType(param.getInvoiceType() == null ? null : String.valueOf(param.getInvoiceType()));
|
info.setRemark(param.getRemark());
|
||||||
dto.setInvoiceContent(param.getInvoiceContent());
|
info.setInvoiceBank(param.getBankName());
|
||||||
dto.setRemark(param.getRemark());
|
info.setInvoiceAccount(param.getBankAccount());
|
||||||
dto.setBankAccount(param.getBankAccount());
|
dao().insert(info);
|
||||||
dto.setRegisteredAddress(param.getRegisteredAddress());
|
|
||||||
dto.setBankName(param.getBankName());
|
|
||||||
|
|
||||||
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2).add("invoiceCode", settlementId),
|
|
||||||
Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds));
|
|
||||||
MallOutboundResult result;
|
|
||||||
boolean requestFailed = false;
|
|
||||||
try {
|
|
||||||
result = mallInvoiceApplyOutboundService.applyInvoice(dto);
|
|
||||||
} catch (Exception e) {
|
|
||||||
requestFailed = true;
|
|
||||||
result = MallOutboundResult.fail(502, e.getMessage());
|
|
||||||
}
|
|
||||||
if (result == null || result.getResultCode() != 0) {
|
|
||||||
PointsMallInvoiceMain current = fetch(invoice.getId());
|
|
||||||
if (current != null && Integer.valueOf(0).equals(current.getBSuccess())) {
|
|
||||||
return "开票已完成,结算单号:" + settlementId;
|
|
||||||
}
|
|
||||||
if (!requestFailed && result != null && result.getResultCode() != 502) {
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
dao().update(PointsMallInvoiceInfo.class, Chain.make("delFlag", true),
|
|
||||||
Cnd.where("mainId", "=", invoice.getId()));
|
|
||||||
dao().update(PointsMallInvoiceMain.class, Chain.make("delFlag", true),
|
|
||||||
Cnd.where("id", "=", invoice.getId()));
|
|
||||||
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 0).add("invoiceCode", ""),
|
|
||||||
Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds)
|
|
||||||
.and("invoiceCode", "=", settlementId).and("invoiceStatus", "in", new Integer[]{0, 2}));
|
|
||||||
});
|
|
||||||
throw new IllegalArgumentException(result.getMessage());
|
|
||||||
}
|
|
||||||
invoice.setBSuccess(1);
|
|
||||||
invoice.setSucOrderIds("");
|
|
||||||
invoice.setFailOrderIds(String.join(",", orderIds));
|
|
||||||
invoice.setFailMsg(result == null ? "供应商开票申请无响应" : result.getMessage());
|
|
||||||
updateIgnoreNull(invoice);
|
|
||||||
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 0),
|
|
||||||
Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds)
|
|
||||||
.and("invoiceCode", "=", settlementId).and("invoiceStatus", "=", 2));
|
|
||||||
throw new IllegalArgumentException(invoice.getFailMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2), Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds));
|
||||||
return "开票申请已生成,结算单号:" + settlementId;
|
return "开票申请已生成,结算单号:" + settlementId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +170,11 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getOrderId())) {
|
if (StrUtil.isNotBlank(param.getOrderId())) {
|
||||||
List<String> orderIds = StrUtil.splitTrim(param.getOrderId(), ",");
|
List<String> orderIds = StrUtil.splitTrim(param.getOrderId(), ",");
|
||||||
|
if (orderIds.size() > 1) {
|
||||||
cnd.and(field(alias, "orderId"), "in", orderIds);
|
cnd.and(field(alias, "orderId"), "in", orderIds);
|
||||||
|
} else {
|
||||||
|
cnd.and(field(alias, "orderId"), "like", "%" + param.getOrderId() + "%");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getStartDate())) {
|
if (StrUtil.isNotBlank(param.getStartDate())) {
|
||||||
cnd.and(field(alias, "orderCompleteTime"), ">=", DateUtil.beginOfDay(DateUtil.parse(param.getStartDate())));
|
cnd.and(field(alias, "orderCompleteTime"), ">=", DateUtil.beginOfDay(DateUtil.parse(param.getStartDate())));
|
||||||
@@ -476,16 +196,16 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
if (StrUtil.isBlank(param.getSupplierId())) {
|
if (StrUtil.isBlank(param.getSupplierId())) {
|
||||||
throw new IllegalArgumentException("供应商不能为空");
|
throw new IllegalArgumentException("供应商不能为空");
|
||||||
}
|
}
|
||||||
|
if (StrUtil.isBlank(param.getOrderIds())) {
|
||||||
|
throw new IllegalArgumentException("订单不能为空");
|
||||||
|
}
|
||||||
if (StrUtil.isBlank(param.getStartDate()) || StrUtil.isBlank(param.getEndDate())) {
|
if (StrUtil.isBlank(param.getStartDate()) || StrUtil.isBlank(param.getEndDate())) {
|
||||||
throw new IllegalArgumentException("订单完成日期不能为空");
|
throw new IllegalArgumentException("订单完成日期不能为空");
|
||||||
}
|
}
|
||||||
if (StrUtil.isBlank(param.getInvoiceDate())) {
|
if (StrUtil.isBlank(param.getInvoiceDate())) {
|
||||||
throw new IllegalArgumentException("开票日期不能为空");
|
throw new IllegalArgumentException("开票日期不能为空");
|
||||||
}
|
}
|
||||||
if (StrUtil.isBlank(param.getInvoiceTitle())) {
|
if (StrUtil.isBlank(param.getInvoiceCode())) {
|
||||||
throw new IllegalArgumentException("发票抬头不能为空");
|
|
||||||
}
|
|
||||||
if (StrUtil.isBlank(param.getTaxIdNumber())) {
|
|
||||||
throw new IllegalArgumentException("纳税人识别号不能为空");
|
throw new IllegalArgumentException("纳税人识别号不能为空");
|
||||||
}
|
}
|
||||||
if (StrUtil.isBlank(param.getInvoiceAddress())) {
|
if (StrUtil.isBlank(param.getInvoiceAddress())) {
|
||||||
@@ -494,8 +214,5 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
|
|||||||
if (StrUtil.isBlank(param.getInvoiceContact())) {
|
if (StrUtil.isBlank(param.getInvoiceContact())) {
|
||||||
throw new IllegalArgumentException("联系电话不能为空");
|
throw new IllegalArgumentException("联系电话不能为空");
|
||||||
}
|
}
|
||||||
if (param.getInvoiceType() == null) {
|
|
||||||
throw new IllegalArgumentException("发票类型不能为空");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-22
@@ -1,7 +1,5 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.controller;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.controller;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.annotation.MallTokenRequired;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.annotation.MallTokenRequired;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*;
|
||||||
@@ -15,7 +13,6 @@ import io.swagger.annotations.Api;
|
|||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.integration.jedis.RedisService;
|
|
||||||
import org.nutz.mvc.adaptor.JsonAdaptor;
|
import org.nutz.mvc.adaptor.JsonAdaptor;
|
||||||
import org.nutz.mvc.annotation.AdaptBy;
|
import org.nutz.mvc.annotation.AdaptBy;
|
||||||
import org.nutz.mvc.annotation.At;
|
import org.nutz.mvc.annotation.At;
|
||||||
@@ -35,25 +32,6 @@ public class PointsMallBridgeController {
|
|||||||
@Inject
|
@Inject
|
||||||
private PointsMallBridgeService pointsMallBridgeService;
|
private PointsMallBridgeService pointsMallBridgeService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private RedisService redisService;
|
|
||||||
|
|
||||||
@POST
|
|
||||||
@At("/connect/supplier-session")
|
|
||||||
@ApiOperation(value = "获取供应商用户会话", notes = "使用 H5 跳转 keyword 换取一次性用户会话")
|
|
||||||
public Result supplierSession(@Param("..") MallSupplierSessionDTO dto) {
|
|
||||||
if (dto == null || StrUtil.isBlank(dto.getKeyword())) {
|
|
||||||
return Result.error("keyword不能为空");
|
|
||||||
}
|
|
||||||
String redisKey = "supplier-session:" + dto.getKeyword();
|
|
||||||
String session = redisService.get(redisKey);
|
|
||||||
if (StrUtil.isBlank(session)) {
|
|
||||||
return Result.error("用户会话不存在或已失效");
|
|
||||||
}
|
|
||||||
redisService.del(redisKey);
|
|
||||||
return Result.success(JSONUtil.parseObj(session));
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@At("/connect/token")
|
@At("/connect/token")
|
||||||
@ApiOperation(value = "获取 token", notes = "供应商获取访问令牌")
|
@ApiOperation(value = "获取 token", notes = "供应商获取访问令牌")
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import java.time.LocalDate;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class InvoiceInfoDTO {
|
public class InvoiceInfoDTO {
|
||||||
private Integer status;
|
|
||||||
private String remark;
|
|
||||||
private String invoiceId;
|
private String invoiceId;
|
||||||
private String invoiceCode;
|
private String invoiceCode;
|
||||||
private LocalDate invoiceDate;
|
private LocalDate invoiceDate;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class MallInvoiceApplyDTO {
|
|||||||
private BigDecimal orderTotalPrice;
|
private BigDecimal orderTotalPrice;
|
||||||
private String invoiceDate;
|
private String invoiceDate;
|
||||||
private String invoiceTitle;
|
private String invoiceTitle;
|
||||||
private String taxIdNumber;
|
private String invoiceCode;
|
||||||
private String invoiceAddress;
|
private String invoiceAddress;
|
||||||
private String invoiceContact;
|
private String invoiceContact;
|
||||||
private BigDecimal invoiceNakedPrice;
|
private BigDecimal invoiceNakedPrice;
|
||||||
|
|||||||
@@ -14,8 +14,5 @@ public class MallOrderEventDTO {
|
|||||||
private String deliveryTime;
|
private String deliveryTime;
|
||||||
private String logisticsOrderId;
|
private String logisticsOrderId;
|
||||||
private String crrgBsnNm;
|
private String crrgBsnNm;
|
||||||
// 接口推送时间,Unix 毫秒时间戳。
|
|
||||||
private Long time;
|
private Long time;
|
||||||
// 本次业务操作发生时间,重推时保留原值,格式 yyyy-MM-dd HH:mm:ss。
|
|
||||||
private String operationTime;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/** 订单消息数据,主单、子单和退货消息统一使用。 */
|
|
||||||
@Data
|
|
||||||
public class MallOrderMessageDTO {
|
|
||||||
private String supplierId;
|
|
||||||
private String userId;
|
|
||||||
private String userName;
|
|
||||||
// 退货消息使用退货单号,pointsPrice 使用本次退款积分。
|
|
||||||
private String orderId;
|
|
||||||
private BigDecimal pointsPrice;
|
|
||||||
private BigDecimal totalPrice;
|
|
||||||
private BigDecimal wPayOrAPay;
|
|
||||||
private Date orderCreateTime;
|
|
||||||
private Date orderFinishTime;
|
|
||||||
// 本次操作时间,取供应商事件的 operationTime,不使用接口推送时间或妥投时间。
|
|
||||||
private Date operationTime;
|
|
||||||
private String extJson;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class MallSupplierSessionDTO {
|
|
||||||
private String keyword;
|
|
||||||
}
|
|
||||||
-44
@@ -1,44 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class OrderInfoByReconciliationDTO {
|
|
||||||
/**
|
|
||||||
* 订单id
|
|
||||||
*/
|
|
||||||
private String orderId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 供应商id
|
|
||||||
*/
|
|
||||||
private String supplierId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品购买总价格(含税价)
|
|
||||||
*/
|
|
||||||
private BigDecimal totalPrice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单消耗积分数,有退货需要计算
|
|
||||||
*/
|
|
||||||
private BigDecimal pointsPrice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单微信支付或支付宝支付数目,有退货需要计算
|
|
||||||
*/
|
|
||||||
private BigDecimal wPayOrAPay;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总价格(不含税)
|
|
||||||
*/
|
|
||||||
private BigDecimal invoiceNakedPrice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下单商品信息
|
|
||||||
*/
|
|
||||||
private List<OrderProInfoDTO> orderProInfos;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import lombok.Data;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class QueryInvoiceInfoDTO {
|
public class QueryInvoiceInfoDTO {
|
||||||
private Boolean retry;
|
|
||||||
private String supplierId;
|
private String supplierId;
|
||||||
private String token;
|
private String token;
|
||||||
private String settlementId;
|
private String settlementId;
|
||||||
|
|||||||
-28
@@ -1,28 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class QueryReconciliationInfoDTO {
|
|
||||||
private String supplierId;
|
|
||||||
private String token;
|
|
||||||
private Integer reconciliationType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单ID
|
|
||||||
*/
|
|
||||||
private String orderId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式为:yyyy-MM-dd(包含单日)
|
|
||||||
*/
|
|
||||||
private String startDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式为:yyyy-MM-dd(包含单日)
|
|
||||||
*/
|
|
||||||
private String endDate;
|
|
||||||
private Integer page;
|
|
||||||
private Integer pageSize;
|
|
||||||
private Long timestamp;
|
|
||||||
}
|
|
||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ReconciliationResultNoticeDTO {
|
|
||||||
private String supplierId;
|
|
||||||
private String token;
|
|
||||||
private Long timestamp;
|
|
||||||
private String reconciliationBatchNo;
|
|
||||||
private String reconciliationTime;
|
|
||||||
private List<ReconciliationResultOrderDTO> reconciliationResults;
|
|
||||||
}
|
|
||||||
-22
@@ -1,22 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ReconciliationResultOrderDTO {
|
|
||||||
private String orderId;
|
|
||||||
private String userId;
|
|
||||||
private Integer reconciliationStatus;
|
|
||||||
private Integer diffType;
|
|
||||||
private String diffReason;
|
|
||||||
private BigDecimal platformTotalPrice;
|
|
||||||
private BigDecimal platformCashAmount;
|
|
||||||
private BigDecimal platformPointsPrice;
|
|
||||||
private BigDecimal platformRefundPrice;
|
|
||||||
private BigDecimal supplierTotalPrice;
|
|
||||||
private BigDecimal supplierCashAmount;
|
|
||||||
private BigDecimal supplierPointsPrice;
|
|
||||||
private BigDecimal supplierRefundPrice;
|
|
||||||
}
|
|
||||||
-1
@@ -7,7 +7,6 @@ public class UnReconciledMsgNoticeDTO {
|
|||||||
private String uniqueSeqNo;
|
private String uniqueSeqNo;
|
||||||
private String supplierId;
|
private String supplierId;
|
||||||
private String token;
|
private String token;
|
||||||
private Long timestamp;
|
|
||||||
private String orderIds;
|
private String orderIds;
|
||||||
private String unReconciledMsg;
|
private String unReconciledMsg;
|
||||||
private String unReconciledType;
|
private String unReconciledType;
|
||||||
|
|||||||
+5
-39
@@ -3,16 +3,7 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
import java.util.Date;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallPointsLockService;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
@@ -21,44 +12,19 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
* MallAbolishSubOrderEventHandler
|
* MallAbolishSubOrderEventHandler
|
||||||
* orderType=8: 废除子订单事件处理器。
|
* orderType=8: 废除子订单事件处理器。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@IocBean
|
||||||
@IocBean(args = {"refer:dao"})
|
public class MallAbolishSubOrderEventHandler implements MallOrderEventHandler {
|
||||||
public class MallAbolishSubOrderEventHandler extends AbstractMallBridgeSupport implements MallOrderEventHandler {
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PointsMallPointsLockService pointsMallPointsLockService;
|
private MallInboundEventService inboundEventService;
|
||||||
|
|
||||||
public MallAbolishSubOrderEventHandler(Dao dao) {
|
|
||||||
super(dao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 废除指定子订单,在同一事务中更新状态并释放或退回积分。
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
Integer state = MallOrderStatusEnum.ABOLISH.getCode();
|
return inboundEventService.updateSubOrderStatus(dto, MallOrderStatusEnum.ABOLISH);
|
||||||
PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "=", dto.getOrderId()).and("delFlag", "=", false));
|
|
||||||
if (sub == null) {
|
|
||||||
return MallInboundResult.fail(404, "订单不存在");
|
|
||||||
}
|
|
||||||
// 已废除的重复通知不再处理,避免重复执行积分释放或退回。
|
|
||||||
if (state.equals(sub.getOrderState())) {
|
|
||||||
log.info("积分商城子单状态已是目标状态,跳过重复处理,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
sub.setOrderState(state);
|
|
||||||
sub.setOrderUpdateTime(new Date());
|
|
||||||
dao.updateIgnoreNull(sub);
|
|
||||||
});
|
|
||||||
log.info("积分商城子单状态更新完成,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-47
@@ -3,18 +3,7 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallPointsLockService;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Chain;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
@@ -22,50 +11,19 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
* MallCancelPayedMainOrderEventHandler
|
* MallCancelPayedMainOrderEventHandler
|
||||||
* orderType=7: 已支付未拆单的整个父单取消。
|
* orderType=7: 已支付未拆单的整个父单取消。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@IocBean
|
||||||
@IocBean(args = {"refer:dao"})
|
public class MallCancelPayedMainOrderEventHandler implements MallOrderEventHandler {
|
||||||
public class MallCancelPayedMainOrderEventHandler extends AbstractMallBridgeSupport implements MallOrderEventHandler {
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PointsMallPointsLockService pointsMallPointsLockService;
|
private MallInboundEventService inboundEventService;
|
||||||
|
|
||||||
public MallCancelPayedMainOrderEventHandler(Dao dao) {
|
|
||||||
super(dao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理已支付未拆单主单取消通知,沿用原 paidNotSplit=true 分支的校验与积分处理。
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
// 优先使用 mainOrderId,未提供时使用事件中的 orderId 查询主订单。
|
return inboundEventService.cancelMainOrder(dto, true);
|
||||||
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
|
|
||||||
if (StrUtil.isBlank(mainOrderId)) {
|
|
||||||
return MallInboundResult.fail(400, "主订单信息不能为空");
|
|
||||||
}
|
|
||||||
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
|
|
||||||
if (main == null) {
|
|
||||||
return MallInboundResult.fail(404, "主订单不存在");
|
|
||||||
}
|
|
||||||
Date now = new Date();
|
|
||||||
// 主子订单状态更新与主单积分锁释放在同一事务内完成。
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
main.setOrderState(ORDER_CANCELLED);
|
|
||||||
main.setOrderUpdateTime(now);
|
|
||||||
dao.updateIgnoreNull(main);
|
|
||||||
// 同步取消该供应商、该主订单下尚未删除的子订单,保持原处理范围。
|
|
||||||
dao.update(PointsMallOrderSub.class, Chain.make("orderState", ORDER_CANCELLED).add("orderUpdateTime", now),
|
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
|
|
||||||
// 使用主订单归属信息释放主单积分锁。
|
|
||||||
pointsMallPointsLockService.releaseMain(main.getUserId(), main.getSupplierId(), main.getOrderId());
|
|
||||||
});
|
|
||||||
log.info("积分商城主单取消完成,supplierId={},mainOrderId={},paidNotSplit={}", dto.getSupplierId(), mainOrderId, true);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-51
@@ -3,18 +3,7 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallPointsLockService;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Chain;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
@@ -22,54 +11,19 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
* MallCancelPendingOrderEventHandler
|
* MallCancelPendingOrderEventHandler
|
||||||
* orderType=1: 取消待支付主单事件处理器。
|
* orderType=1: 取消待支付主单事件处理器。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@IocBean
|
||||||
@IocBean(args = {"refer:dao"})
|
public class MallCancelPendingOrderEventHandler implements MallOrderEventHandler {
|
||||||
public class MallCancelPendingOrderEventHandler extends AbstractMallBridgeSupport implements MallOrderEventHandler {
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PointsMallPointsLockService pointsMallPointsLockService;
|
private MallInboundEventService inboundEventService;
|
||||||
|
|
||||||
public MallCancelPendingOrderEventHandler(Dao dao) {
|
|
||||||
super(dao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理待支付主单取消通知,校验待支付状态后取消订单并释放主单积分锁。
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
// 优先使用 mainOrderId,未提供时使用事件中的 orderId 查询主订单。
|
return inboundEventService.cancelMainOrder(dto, false);
|
||||||
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
|
|
||||||
if (StrUtil.isBlank(mainOrderId)) {
|
|
||||||
return MallInboundResult.fail(400, "主订单信息不能为空");
|
|
||||||
}
|
|
||||||
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
|
|
||||||
if (main == null) {
|
|
||||||
return MallInboundResult.fail(404, "主订单不存在");
|
|
||||||
}
|
|
||||||
// 待支付取消事件仅允许取消尚未支付的主订单。
|
|
||||||
if (!Integer.valueOf(ORDER_PENDING_PAY).equals(main.getOrderState())) {
|
|
||||||
return MallInboundResult.fail(400, "只能取消未支付主单");
|
|
||||||
}
|
|
||||||
Date now = new Date();
|
|
||||||
// 主子订单状态更新与主单积分锁释放在同一事务内完成。
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
main.setOrderState(ORDER_CANCELLED);
|
|
||||||
main.setOrderUpdateTime(now);
|
|
||||||
dao.updateIgnoreNull(main);
|
|
||||||
// 同步取消该供应商、该主订单下尚未删除的子订单,保持原处理范围。
|
|
||||||
dao.update(PointsMallOrderSub.class, Chain.make("orderState", ORDER_CANCELLED).add("orderUpdateTime", now),
|
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
|
|
||||||
// 使用主订单归属信息释放主单积分锁。
|
|
||||||
pointsMallPointsLockService.releaseMain(main.getUserId(), main.getSupplierId(), main.getOrderId());
|
|
||||||
});
|
|
||||||
log.info("积分商城主单取消完成,supplierId={},mainOrderId={},paidNotSplit={}", dto.getSupplierId(), mainOrderId, false);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -1,8 +1,6 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderMessageDTO;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import com.budwk.app.sys.models.Sys_user;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
@@ -63,7 +61,7 @@ public class MallCancelSubOrderEventHandler implements MallOrderEventHandler {
|
|||||||
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getOrderId(), dto.getUserId())) {
|
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getOrderId(), dto.getUserId())) {
|
||||||
return MallInboundResult.fail(400, "供应商、订单、用户不能为空");
|
return MallInboundResult.fail(400, "供应商、订单、用户不能为空");
|
||||||
}
|
}
|
||||||
// 供应商传入 userId 为虚拟用户ID,转换为系统用户后用于消息推送。
|
// userId 兼容系统用户ID和工号,后续消息推送需要使用用户信息。
|
||||||
Sys_user user = fetchUser(dto.getUserId());
|
Sys_user user = fetchUser(dto.getUserId());
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return MallInboundResult.fail(-1, "用户不存在");
|
return MallInboundResult.fail(-1, "用户不存在");
|
||||||
@@ -104,10 +102,7 @@ public class MallCancelSubOrderEventHandler implements MallOrderEventHandler {
|
|||||||
pointsMallOrderService.updateMainOrderStatus(sub.getMainOrderId(), sub.getSupplierId());
|
pointsMallOrderService.updateMainOrderStatus(sub.getMainOrderId(), sub.getSupplierId());
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
MallOrderMessageDTO message = BeanUtil.copyProperties(sub, MallOrderMessageDTO.class);
|
mallCallPMessagePushService.pushMessageToGlobal(StrUtil.blankToDefault(user.getUsername(), user.getLoginname()), sub);
|
||||||
message.setOperationTime(StrUtil.isBlank(dto.getOperationTime()) ? null : DateUtil.parse(dto.getOperationTime().replace("T", " ")));
|
|
||||||
message.setUserName(StrUtil.blankToDefault(user.getUsername(), user.getLoginname()));
|
|
||||||
mallCallPMessagePushService.pushMessageToGlobal("66666666", message);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("9.2.1 子单取消,callP消息推送:{},{}", dto, e.getMessage());
|
log.error("9.2.1 子单取消,callP消息推送:{},{}", dto, e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -115,8 +110,14 @@ public class MallCancelSubOrderEventHandler implements MallOrderEventHandler {
|
|||||||
return MallInboundResult.success();
|
return MallInboundResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Sys_user fetchUser(String virtualId) {
|
/**
|
||||||
return dao.fetch(Sys_user.class, Cnd.where("virtual_id", "=", virtualId)
|
* 入参 userId 可能是系统用户ID或工号,按当前项目用户表兼容查询。
|
||||||
.and("disabled", "=", false).and("delFlag", "=", false));
|
*/
|
||||||
|
private Sys_user fetchUser(String userId) {
|
||||||
|
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", userId).and("disabled", "=", false).and("delFlag", "=", false));
|
||||||
|
if (user != null) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
return dao.fetch(Sys_user.class, Cnd.where("loginname", "=", userId).and("disabled", "=", false).and("delFlag", "=", false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-106
@@ -1,26 +1,9 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderMessageDTO;
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
import java.util.Date;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallOrderQueryOutboundService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallCallPMessagePushService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
@@ -33,103 +16,19 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
* <p>注意:供应商侧“确认收货”对应 zhgh/callP 侧“已妥投(4)”,
|
* <p>注意:供应商侧“确认收货”对应 zhgh/callP 侧“已妥投(4)”,
|
||||||
* 不等同于 zhgh/callP 用户确认收货后的“已完成(5)”。</p>
|
* 不等同于 zhgh/callP 用户确认收货后的“已完成(5)”。</p>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@IocBean
|
||||||
@IocBean(args = {"refer:dao"})
|
public class MallConfirmReceiptEventHandler implements MallOrderEventHandler {
|
||||||
public class MallConfirmReceiptEventHandler extends AbstractMallBridgeSupport implements MallOrderEventHandler {
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private MallOrderQueryOutboundService mallOrderQueryOutboundService;
|
private MallInboundEventService inboundEventService;
|
||||||
@Inject
|
|
||||||
private MallCallPMessagePushService mallCallPMessagePushService;
|
|
||||||
|
|
||||||
public MallConfirmReceiptEventHandler(Dao dao) {
|
|
||||||
super(dao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理供应商确认收货通知,仅更新为已妥投,不执行用户确认完成后的积分扣减。
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
Integer state = MallOrderStatusEnum.RECEIVED.getCode();
|
return inboundEventService.updateSubOrderStatus(dto, MallOrderStatusEnum.RECEIVED);
|
||||||
PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "=", dto.getOrderId()).and("delFlag", "=", false));
|
|
||||||
if (sub == null) {
|
|
||||||
return MallInboundResult.fail(404, "订单不存在");
|
|
||||||
}
|
|
||||||
// 已妥投的重复通知直接返回,保留原处理的幂等行为。
|
|
||||||
if (state.equals(sub.getOrderState())) {
|
|
||||||
log.info("积分商城子单状态已是目标状态,跳过重复处理,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
// 补查供应商订单详情;查询失败时沿用原逻辑,仍更新本地妥投状态。
|
|
||||||
fillReceivedSubOrder(dto, sub);
|
|
||||||
sub.setOrderState(state);
|
|
||||||
// 优先保留订单详情中的时间,缺失时使用当前时间。
|
|
||||||
if (sub.getOrderUpdateTime() == null) {
|
|
||||||
sub.setOrderUpdateTime(new Date());
|
|
||||||
}
|
|
||||||
if (sub.getOrderFinishTime() == null) {
|
|
||||||
sub.setOrderFinishTime(new Date());
|
|
||||||
}
|
|
||||||
dao.updateIgnoreNull(sub);
|
|
||||||
});
|
|
||||||
// 妥投状态保存成功后发送提醒,消息异常不回滚订单处理。
|
|
||||||
try {
|
|
||||||
// 按子订单所属用户读取姓名,显式传入妥投提醒的 userName 模板变量。
|
|
||||||
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", sub.getUserId()).or("loginname", "=", sub.getUserId()));
|
|
||||||
if (user == null) {
|
|
||||||
throw new IllegalArgumentException("订单所属用户不存在,无法生成妥投提醒");
|
|
||||||
}
|
|
||||||
MallOrderMessageDTO message = BeanUtil.copyProperties(sub, MallOrderMessageDTO.class);
|
|
||||||
message.setOperationTime(parseDate(dto.getOperationTime()));
|
|
||||||
message.setUserName(StrUtil.blankToDefault(user.getUsername(), user.getLoginname()));
|
|
||||||
mallCallPMessagePushService.pushMessageToGlobal("22222222", message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("订单类型为:6(确认收货)时,全局消息推送失败:{}", dto, e);
|
|
||||||
}
|
|
||||||
log.info("积分商城子单状态更新完成,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单类型为:6(确认收货)时,调用 9.2.2 获取订单详情接口,补充子单妥投相关信息。
|
|
||||||
*
|
|
||||||
* <p>供应商侧确认收货只代表电商处已收货,对 zhgh/callP 侧应更新为已妥投(4),
|
|
||||||
* 等待 callP 用户侧确认收货后才进入已完成(5)。</p>
|
|
||||||
*/
|
|
||||||
private void fillReceivedSubOrder(MallOrderEventDTO dto, PointsMallOrderSub sub) {
|
|
||||||
if (mallOrderQueryOutboundService == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MallOrderQueryDTO queryDTO = new MallOrderQueryDTO();
|
|
||||||
queryDTO.setSupplierId(dto.getSupplierId());
|
|
||||||
queryDTO.setOrderId(dto.getOrderId());
|
|
||||||
queryDTO.setOrderType(2);
|
|
||||||
log.info("订单类型为:6(确认收货)时,调用9.2.2获取订单详情接口:{}", queryDTO);
|
|
||||||
try {
|
|
||||||
MallOutboundResult result = mallOrderQueryOutboundService.queryOrderInfo(queryDTO);
|
|
||||||
if (result == null || result.getResultCode() != 0 || result.getOrderInfo() == null || result.getOrderInfo().isEmpty()) {
|
|
||||||
log.error("订单类型为:6(确认收货)时,调用9.2.2 获取订单详情失败:{},{}", queryDTO, result == null ? null : result.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
OrderInfoDTO orderInfo = result.getOrderInfo().get(0);
|
|
||||||
sub.setOrderCreateTime(parseDate(orderInfo.getCreateTime()));
|
|
||||||
sub.setOrderUpdateTime(parseDate(orderInfo.getUpdateTime()));
|
|
||||||
sub.setOrderFinishTime(parseDate(orderInfo.getOrderFinishTime()));
|
|
||||||
sub.setDeliveryTime(parseDate(orderInfo.getDeliveryTime()));
|
|
||||||
sub.setDeliveryStatus(parseInteger(orderInfo.getDeliveryStatus()));
|
|
||||||
if (orderInfo.getOrderProInfos() != null) {
|
|
||||||
sub.setExtJson(JSONUtil.toJsonStr(orderInfo.getOrderProInfos()));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("订单类型为:6(确认收货)时,调用9.2.2 获取订单详情异常:{},{}", queryDTO, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.invoice.service.PointsMallInvoiceService;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
public class MallInvoiceInfoEventHandler implements MallOrderEventHandler {
|
public class MallInvoiceInfoEventHandler implements MallOrderEventHandler {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PointsMallInvoiceService pointsMallInvoiceService;
|
private MallInboundEventService inboundEventService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
@@ -24,6 +24,6 @@ public class MallInvoiceInfoEventHandler implements MallOrderEventHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
return pointsMallInvoiceService.invoiceInfo(dto);
|
return inboundEventService.invoiceInfo(dto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-96
@@ -3,116 +3,27 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInboundEventService;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Chain;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.trans.Atom;
|
|
||||||
import org.nutz.trans.Trans;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MallShipOrderEventHandler
|
* MallShipOrderEventHandler
|
||||||
* orderType=99: 供应商已发货 / 更新发货状态。
|
* orderType=99: 供应商已发货 / 更新发货状态。
|
||||||
* 在处理器内完成订单校验及主子订单物流信息更新,不再回调事件分发服务。
|
|
||||||
* 本事件仅更新发货状态和物流信息,不修改订单业务状态 orderState。
|
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@IocBean
|
||||||
@IocBean(args = {"refer:dao"})
|
public class MallShipOrderEventHandler implements MallOrderEventHandler {
|
||||||
public class MallShipOrderEventHandler extends AbstractMallBridgeSupport implements MallOrderEventHandler {
|
|
||||||
|
|
||||||
public MallShipOrderEventHandler(Dao dao) {
|
@Inject
|
||||||
super(dao);
|
private MallInboundEventService inboundEventService;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return 99;
|
return 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理供应商发货通知,在同一事务中更新匹配的子订单及一个主订单。
|
|
||||||
*
|
|
||||||
* @param dto 发货事件,orderId 为英文逗号分隔的子订单号,userId 为可选的用户虚拟 ID
|
|
||||||
* @return 参数或用户映射无效时返回 400,无匹配子订单时返回 404,更新完成返回成功
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public MallInboundResult handle(MallOrderEventDTO dto) {
|
public MallInboundResult handle(MallOrderEventDTO dto) {
|
||||||
if (StrUtil.isBlank(dto.getSupplierId()) || StrUtil.isBlank(dto.getOrderId())) {
|
return inboundEventService.updateDeliveryStatus(dto);
|
||||||
return MallInboundResult.fail(400, "供应商或订单不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按供应商和明确的子订单号限定更新范围,支持一次通知多个子订单。
|
|
||||||
List<String> orderIds = splitIds(dto.getOrderId());
|
|
||||||
if (orderIds.isEmpty()) {
|
|
||||||
return MallInboundResult.fail(400, "订单信息不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未提供有效发货时间时,使用当前处理时间。
|
|
||||||
Date deliveryTime = parseDate(dto.getDeliveryTime());
|
|
||||||
if (deliveryTime == null) {
|
|
||||||
deliveryTime = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
Cnd subCnd = Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "in", orderIds)
|
|
||||||
.and("delFlag", "=", false);
|
|
||||||
if (StrUtil.isNotBlank(dto.getUserId())) {
|
|
||||||
// 供应商传入虚拟 ID,转换为本地用户 ID 后参与订单归属查询。
|
|
||||||
Sys_user user = fetchUser(dto.getUserId());
|
|
||||||
if (user == null) {
|
|
||||||
return MallInboundResult.fail(400, "用户ID未配置或不存在");
|
|
||||||
}
|
|
||||||
subCnd.and("userId", "=", user.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PointsMallOrderSub> subs = dao.query(PointsMallOrderSub.class, subCnd);
|
|
||||||
if (subs.isEmpty()) {
|
|
||||||
return MallInboundResult.fail(404, "订单不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
Date finalDeliveryTime = deliveryTime;
|
|
||||||
// 已发货事件固定写入 deliveryStatus=1,不使用通知中的状态值覆盖该语义。
|
|
||||||
Integer deliveredStatus = 1;
|
|
||||||
Trans.exec((Atom) () -> {
|
|
||||||
// 物流单号和承运商仅在非空时更新,避免空字段覆盖已有物流信息。
|
|
||||||
Chain subChain = Chain.make("deliveryStatus", deliveredStatus)
|
|
||||||
.add("deliveryTime", finalDeliveryTime);
|
|
||||||
if (StrUtil.isNotBlank(dto.getLogisticsOrderId())) {
|
|
||||||
subChain.add("logisticsOrderId", dto.getLogisticsOrderId());
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(dto.getCrrgBsnNm())) {
|
|
||||||
subChain.add("crrgBsnNm", dto.getCrrgBsnNm());
|
|
||||||
}
|
|
||||||
dao.update(PointsMallOrderSub.class, subChain, subCnd);
|
|
||||||
|
|
||||||
// 优先使用通知中的主订单号,未提供时取首个匹配子订单的主订单号。
|
|
||||||
// 此处只同步该主订单的物流信息,不检查其余子订单是否全部发货。
|
|
||||||
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), subs.get(0).getMainOrderId());
|
|
||||||
if (StrUtil.isNotBlank(mainOrderId)) {
|
|
||||||
// 主订单的发货状态字段为字符串,子订单字段为整数。
|
|
||||||
Chain mainChain = Chain.make("deliveryStatus", String.valueOf(deliveredStatus))
|
|
||||||
.add("deliveryTime", finalDeliveryTime);
|
|
||||||
if (StrUtil.isNotBlank(dto.getLogisticsOrderId())) {
|
|
||||||
mainChain.add("logisticsOrderId", dto.getLogisticsOrderId());
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(dto.getCrrgBsnNm())) {
|
|
||||||
mainChain.add("crrgBsnNm", dto.getCrrgBsnNm());
|
|
||||||
}
|
|
||||||
dao.update(PointsMallOrderMain.class, mainChain, Cnd.where("supplierId", "=", dto.getSupplierId())
|
|
||||||
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.info("供应商已发货事件处理完成,supplierId={},mainOrderId={},orderIds={},deliveryStatus={}",
|
|
||||||
dto.getSupplierId(), dto.getMainOrderId(), orderIds, deliveredStatus);
|
|
||||||
return MallInboundResult.success();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -94,7 +94,7 @@ public class MallSplitSubOrderEventHandler implements MallOrderEventHandler {
|
|||||||
// 调用外部服务获取子订单信息
|
// 调用外部服务获取子订单信息
|
||||||
MallOutboundResult result = mallOrderQueryOutboundService.orderQuery(queryDTO);
|
MallOutboundResult result = mallOrderQueryOutboundService.orderQuery(queryDTO);
|
||||||
if (result == null || result.getResultCode() != 0) {
|
if (result == null || result.getResultCode() != 0) {
|
||||||
return MallInboundResult.fail(result == null ? 502 : result.getResultCode(), result == null ? "获取订单详情返回为空" : result.getMessage());
|
throw new RuntimeException(result == null ? "获取订单详情返回为空" : result.getMessage());
|
||||||
}
|
}
|
||||||
orderInfoList = result.getOrderInfo();
|
orderInfoList = result.getOrderInfo();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
+2
-5
@@ -1,5 +1,4 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderMessageDTO;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@@ -149,15 +148,13 @@ public class MallSubOrderReturnEventHandler extends AbstractMallBridgeSupport im
|
|||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
// callP消息推送
|
// callP消息推送
|
||||||
MallOrderMessageDTO notifySub = BeanUtil.copyProperties(sub, MallOrderMessageDTO.class);
|
PointsMallOrderSub notifySub = BeanUtil.copyProperties(sub, PointsMallOrderSub.class);
|
||||||
notifySub.setOperationTime(parseDate(dto.getOperationTime()));
|
|
||||||
notifySub.setOrderId(dto.getOrderId());
|
notifySub.setOrderId(dto.getOrderId());
|
||||||
notifySub.setPointsPrice(refund);
|
notifySub.setPointsPrice(refund);
|
||||||
notifySub.setTotalPrice(orderInfo.getTotalPrice());
|
notifySub.setTotalPrice(orderInfo.getTotalPrice());
|
||||||
notifySub.setWPayOrAPay(orderInfo.getWPayOrAPay());
|
notifySub.setWPayOrAPay(orderInfo.getWPayOrAPay());
|
||||||
notifySub.setExtJson(orderExchange.getExtJson());
|
notifySub.setExtJson(orderExchange.getExtJson());
|
||||||
notifySub.setUserName(StrUtil.blankToDefault(user.getUsername(), user.getLoginname()));
|
mallCallPMessagePushService.pushMessageToGlobal(StrUtil.blankToDefault(user.getUsername(), user.getLoginname()), notifySub);
|
||||||
mallCallPMessagePushService.pushMessageToGlobal("66666666", notifySub);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("9.2.1 子单取消 或 退货,callP消息推送: {}, {}", dto, e.getMessage());
|
log.error("9.2.1 子单取消 或 退货,callP消息推送: {}, {}", dto, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
-55
@@ -1,55 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.model;
|
|
||||||
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoByReconciliationDTO;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class MallOutboundPageResult {
|
|
||||||
/**
|
|
||||||
* 0: 查询成功, 其他: 响应失败错误码
|
|
||||||
*/
|
|
||||||
private int resultCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败时, 返回失败原因
|
|
||||||
*/
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总页
|
|
||||||
*/
|
|
||||||
private Integer totalPage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前页
|
|
||||||
*/
|
|
||||||
private Integer currentPage;
|
|
||||||
|
|
||||||
//9.2.2 获取订单详情接口时不能为空
|
|
||||||
private List<OrderInfoByReconciliationDTO> orderInfos;
|
|
||||||
|
|
||||||
public static MallOutboundPageResult success() {
|
|
||||||
MallOutboundPageResult r = new MallOutboundPageResult();
|
|
||||||
r.resultCode = 0;
|
|
||||||
r.message = "成功";
|
|
||||||
r.orderInfos = null;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MallOutboundPageResult success(List<OrderInfoByReconciliationDTO> o) {
|
|
||||||
MallOutboundPageResult r = new MallOutboundPageResult();
|
|
||||||
r.resultCode = 0;
|
|
||||||
r.message = "成功";
|
|
||||||
r.orderInfos = o;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MallOutboundPageResult fail(int code, String message) {
|
|
||||||
MallOutboundPageResult r = new MallOutboundPageResult();
|
|
||||||
r.resultCode = code;
|
|
||||||
r.message = message;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+104
-91
@@ -8,7 +8,8 @@ import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessage;
|
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessage;
|
||||||
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessageTemplate;
|
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessageTemplate;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderMessageDTO;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
@@ -38,111 +39,123 @@ public class MallCallPMessagePushService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一订单消息入口:11111111 支付成功,22222222 妥投提醒,66666666 积分退回。
|
* 支付成功callP消息推送。
|
||||||
* 主单、子单均转换为 MallOrderMessageDTO,退货传入退货单号及本次退款积分。
|
*
|
||||||
* 已成功消息不重复发送;失败记录可在再次调用时重用。
|
* @param mainOrder 订单信息
|
||||||
* synchronized 防止当前服务实例内的并发通知重复创建消息。
|
|
||||||
*/
|
*/
|
||||||
public synchronized void pushMessageToGlobal(String templateId, MallOrderMessageDTO order) {
|
public void pushMessageToGlobal(PointsMallOrderMain mainOrder) {
|
||||||
if (order == null || StrUtil.hasBlank(templateId, order.getSupplierId(), order.getUserId(), order.getOrderId())) {
|
PointsMallMessageTemplate template = dao.fetch(PointsMallMessageTemplate.class, Cnd.where("id", "=", "11111111").and("delFlag", "=", false));
|
||||||
throw new IllegalArgumentException("消息模板、供应商、用户和订单不能为空");
|
if (template == null) {
|
||||||
}
|
log.info("支付成功推送消息失败,未配置消息模板");
|
||||||
if ("66666666".equals(templateId) && nvl(order.getPointsPrice()).signum() <= 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String userId = order.getUserId();
|
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", mainOrder.getUserId()).or("loginname", "=", mainOrder.getUserId()));
|
||||||
Date now = new Date();
|
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class, Cnd.where("supplierId", "=", mainOrder.getSupplierId()).and("delFlag", "=", false));
|
||||||
Date finishTime = "11111111".equals(templateId) ? order.getOrderCreateTime()
|
String supplierName = supplier == null || StrUtil.isBlank(supplier.getSupplierName()) ? mainOrder.getSupplierId() : supplier.getSupplierName();
|
||||||
: order.getOrderFinishTime() == null ? now : order.getOrderFinishTime();
|
// 消息唯一标识 模板id+供应商+订单号
|
||||||
Date planPushTime = now;
|
String uniqueNo = template.getId().concat("-").concat(mainOrder.getSupplierId()).concat("-").concat(mainOrder.getOrderId());
|
||||||
String uniqueNo = templateId + "-" + order.getSupplierId() + "-" + order.getOrderId();
|
int count = dao.count(PointsMallMessage.class, Cnd.where("uniqueNo", "=", uniqueNo).and("delFlag", "=", false));
|
||||||
if ("22222222".equals(templateId)) {
|
if (count > 0) {
|
||||||
// 妥投提醒按自然日去重;取消、退货按业务订单号去重。
|
log.info("9.2.14支付结果通知接口-支付成功2,消息重复推送:{}", uniqueNo);
|
||||||
if (DateUtil.beginOfDay(finishTime).after(DateUtil.beginOfDay(now))) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long day = DateUtil.betweenDay(DateUtil.beginOfDay(finishTime), DateUtil.beginOfDay(now), false);
|
|
||||||
uniqueNo += "-" + day;
|
StringBuilder sb = new StringBuilder();
|
||||||
planPushTime = DateUtil.offsetDay(finishTime, (int) day);
|
sb.append(" 商品列表:").append(System.lineSeparator());
|
||||||
}
|
List<OrderProInfoDTO> productList = StrUtil.isBlank(mainOrder.getExtJson())
|
||||||
PointsMallMessageTemplate template = dao.fetch(PointsMallMessageTemplate.class,
|
? Collections.emptyList()
|
||||||
Cnd.where("id", "=", templateId).and("delFlag", "=", false));
|
: JSONUtil.toList(mainOrder.getExtJson(), OrderProInfoDTO.class);
|
||||||
if (template == null || StrUtil.isBlank(template.getContent())) {
|
productList.forEach(product ->
|
||||||
log.info("订单消息推送失败,未配置消息模板或模板内容为空,templateId={}", templateId);
|
sb.append(" 商品名称:").append(product.getName()).append(",商品价格:").append(formatMoney(product.getPrice())).append("元").append(System.lineSeparator())
|
||||||
return;
|
);
|
||||||
}
|
// 模板变量替换数据
|
||||||
PointsMallMessage message = dao.fetch(PointsMallMessage.class,
|
Map<String, String> paramMap = new HashMap<>();
|
||||||
Cnd.where("uniqueNo", "=", uniqueNo).and("delFlag", "=", false));
|
paramMap.put("#{userName}", user == null || StrUtil.isBlank(user.getUsername()) ? mainOrder.getUserId() : user.getUsername());
|
||||||
if (message != null && Integer.valueOf(1).equals(message.getStatus())) {
|
paramMap.put("#{orderFinishTime}", DateUtil.formatDateTime(mainOrder.getOrderCreateTime()));
|
||||||
log.info("订单消息已推送,跳过重复通知:{}", uniqueNo);
|
paramMap.put("#{pointPrice}", nvl(mainOrder.getPointsPrice()).toPlainString());
|
||||||
return;
|
paramMap.put("#{supplierName}", supplierName);
|
||||||
}
|
paramMap.put("#{totalPrice}", nvl(mainOrder.getTotalPrice()).toPlainString());
|
||||||
Map<String, String> params = orderParams(order.getSupplierId(), userId, order.getExtJson(),
|
paramMap.put("#{payPrice}", nvl(mainOrder.getWPayOrAPay()).toPlainString());
|
||||||
"11111111".equals(templateId), order.getTotalPrice());
|
paramMap.put("#{productList}", sb.toString());
|
||||||
if (StrUtil.isNotBlank(order.getUserName())) {
|
|
||||||
params.put("#{userName}", order.getUserName());
|
// 模板转换成具体的消息
|
||||||
}
|
|
||||||
params.put("#{orderId}", order.getOrderId());
|
|
||||||
params.put("#{orderFinishTime}", finishTime == null ? "" : DateUtil.formatDateTime(finishTime));
|
|
||||||
params.put("#{operationTime}", order.getOperationTime() == null ? "" : DateUtil.formatDateTime(order.getOperationTime()));
|
|
||||||
params.put("#{pointPrice}", nvl(order.getPointsPrice()).toPlainString());
|
|
||||||
params.put("#{totalPrice}", nvl(order.getTotalPrice()).toPlainString());
|
|
||||||
params.put("#{payPrice}", nvl(order.getWPayOrAPay()).toPlainString());
|
|
||||||
String content = template.getContent();
|
String content = template.getContent();
|
||||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
|
||||||
content = content.replace(entry.getKey(), StrUtil.blankToDefault(entry.getValue(), ""));
|
content = content.replace(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
boolean create = message == null;
|
// 生成记录
|
||||||
if (create) {
|
PointsMallMessage message = new PointsMallMessage();
|
||||||
message = new PointsMallMessage();
|
|
||||||
message.setUniqueNo(uniqueNo);
|
message.setUniqueNo(uniqueNo);
|
||||||
}
|
|
||||||
message.setPushType("CALLP");
|
message.setPushType("CALLP");
|
||||||
message.setTemplateId(templateId);
|
message.setTemplateId(template.getId());
|
||||||
message.setTouser(userId);
|
message.setTouser(mainOrder.getUserId());
|
||||||
|
message.setContent(content);
|
||||||
|
message.setContentLink(template.getContentLink());
|
||||||
|
message.setPlanPushTime(new Date());
|
||||||
|
// 状态设置为已推送
|
||||||
|
message.setStatus(1);
|
||||||
|
dao.insert(message);
|
||||||
|
|
||||||
|
globalMessageSendService.sendLocalSystemMessage(template.getName(), content, 1, Collections.singletonList(mainOrder.getUserId()), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callP消息推送。
|
||||||
|
*
|
||||||
|
* @param userName 用户姓名
|
||||||
|
* @param subOrder 订单信息
|
||||||
|
*/
|
||||||
|
public void pushMessageToGlobal(String userName, PointsMallOrderSub subOrder) {
|
||||||
|
PointsMallMessageTemplate template = dao.fetch(PointsMallMessageTemplate.class, Cnd.where("id", "=", "22222222").and("delFlag", "=", false));
|
||||||
|
if (template == null) {
|
||||||
|
log.info("子单取消后推送消息失败,未配置消息模板");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class, Cnd.where("supplierId", "=", subOrder.getSupplierId()).and("delFlag", "=", false));
|
||||||
|
String supplierName = supplier == null || StrUtil.isBlank(supplier.getSupplierName()) ? subOrder.getSupplierId() : supplier.getSupplierName();
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
Date finishTime = subOrder.getOrderFinishTime() == null ? now : subOrder.getOrderFinishTime();
|
||||||
|
long day = DateUtil.betweenDay(DateUtil.beginOfDay(finishTime), DateUtil.beginOfDay(now), false);
|
||||||
|
String uniqueNo = template.getId().concat("-").concat(subOrder.getSupplierId()).concat("-")
|
||||||
|
.concat(subOrder.getOrderId()).concat("-").concat(String.valueOf(day));
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("商品列表: ").append(System.lineSeparator());
|
||||||
|
List<OrderProInfoDTO> productList = StrUtil.isBlank(subOrder.getExtJson())
|
||||||
|
? Collections.emptyList()
|
||||||
|
: JSONUtil.toList(subOrder.getExtJson(), OrderProInfoDTO.class);
|
||||||
|
productList.forEach(product ->
|
||||||
|
sb.append(" 商品名称: ").append(product.getName()).append(",商品价格:").append(formatMoney(product.getPrice())).append("元").append(System.lineSeparator())
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, String> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("#{userName}", userName);
|
||||||
|
paramMap.put("#{orderFinishTime}", DateUtil.formatDateTime(finishTime));
|
||||||
|
paramMap.put("#{pointPrice}", nvl(subOrder.getPointsPrice()).toPlainString());
|
||||||
|
paramMap.put("#{supplierName}", supplierName);
|
||||||
|
paramMap.put("#{totalPrice}", nvl(subOrder.getTotalPrice()).toPlainString());
|
||||||
|
paramMap.put("#{payPrice}", nvl(subOrder.getWPayOrAPay()).toPlainString());
|
||||||
|
paramMap.put("#{productList}", sb.toString());
|
||||||
|
|
||||||
|
String content = template.getContent();
|
||||||
|
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
|
||||||
|
content = content.replace(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
Date planPushTime = DateUtil.offsetDay(finishTime, (int) day);
|
||||||
|
PointsMallMessage message = new PointsMallMessage();
|
||||||
|
message.setUniqueNo(uniqueNo);
|
||||||
|
message.setPushType("CALLP");
|
||||||
|
message.setTemplateId(template.getId());
|
||||||
|
message.setTouser(subOrder.getUserId());
|
||||||
message.setContent(content);
|
message.setContent(content);
|
||||||
message.setContentLink(template.getContentLink());
|
message.setContentLink(template.getContentLink());
|
||||||
message.setPlanPushTime(planPushTime);
|
message.setPlanPushTime(planPushTime);
|
||||||
message.setStatus(0);
|
message.setStatus(0);
|
||||||
if (create) {
|
|
||||||
dao.insert(message);
|
dao.insert(message);
|
||||||
} else {
|
|
||||||
dao.updateIgnoreNull(message);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
globalMessageSendService.sendLocalSystemMessage(template.getName(), content, 1, Collections.singletonList(userId), null);
|
|
||||||
message.setStatus(1);
|
|
||||||
dao.updateIgnoreNull(message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
message.setStatus(2);
|
|
||||||
dao.updateIgnoreNull(message);
|
|
||||||
throw new IllegalStateException("订单消息推送失败:" + uniqueNo, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 公共模板变量:用户姓名、供应商名称和订单商品列表。 */
|
globalMessageSendService.sendLocalSystemMessage(template.getName(), content, 1, Collections.singletonList(subOrder.getUserId()), null);
|
||||||
private Map<String, String> orderParams(String supplierId, String userId, String extJson,
|
|
||||||
boolean paymentMessage, BigDecimal totalPrice) {
|
|
||||||
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", userId).or("loginname", "=", userId));
|
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class, Cnd.where("supplierId", "=", supplierId).and("delFlag", "=", false));
|
|
||||||
Map<String, String> params = new HashMap<>();
|
|
||||||
params.put("#{userName}", user == null ? userId : StrUtil.blankToDefault(user.getUsername(), userId));
|
|
||||||
params.put("#{supplierName}", supplier == null ? supplierId : StrUtil.blankToDefault(supplier.getSupplierName(), supplierId));
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(paymentMessage ? "商品列表:" : "商品列表: ").append(System.lineSeparator());
|
|
||||||
List<OrderProInfoDTO> products = StrUtil.isBlank(extJson) || "null".equalsIgnoreCase(extJson.trim())
|
|
||||||
? Collections.emptyList() : JSONUtil.toList(extJson, OrderProInfoDTO.class);
|
|
||||||
if (paymentMessage) {
|
|
||||||
products.forEach(product -> sb.append("商品名称:").append(product.getName())
|
|
||||||
.append(" * ").append(product.getNumber() == null ? "-" : product.getNumber())
|
|
||||||
.append(",商品单价:").append(formatMoney(product.getPrice())).append("元").append(System.lineSeparator()));
|
|
||||||
sb.append(System.lineSeparator()).append("订单合计:¥").append(formatMoney(totalPrice));
|
|
||||||
} else {
|
|
||||||
products.forEach(product -> sb.append(" 商品名称: ").append(product.getName())
|
|
||||||
.append(",商品价格:").append(formatMoney(product.getPrice())).append("元").append(System.lineSeparator()));
|
|
||||||
}
|
|
||||||
params.put("#{productList}", sb.toString());
|
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatMoney(BigDecimal value) {
|
private String formatMoney(BigDecimal value) {
|
||||||
|
|||||||
+322
-5
@@ -1,6 +1,11 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallAbolishSubOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallAbolishSubOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallCancelPayedMainOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallCancelPayedMainOrderEventHandler;
|
||||||
@@ -13,15 +18,28 @@ import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallShipOrderEven
|
|||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallSplitSubOrderEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallSplitSubOrderEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallSubOrderReturnEventHandler;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallSubOrderReturnEventHandler;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallPointsLockService;
|
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallPointsLockService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Chain;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.trans.Atom;
|
||||||
|
import org.nutz.trans.Trans;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商城桥接订单事件入站服务。
|
* 商城桥接订单事件入站服务。
|
||||||
@@ -35,10 +53,6 @@ public class MallInboundEventService extends AbstractMallBridgeSupport {
|
|||||||
@Inject
|
@Inject
|
||||||
private MallOrderQueryOutboundService mallOrderQueryOutboundService;
|
private MallOrderQueryOutboundService mallOrderQueryOutboundService;
|
||||||
@Inject
|
@Inject
|
||||||
private MallInvoiceInfoQueryService mallInvoiceInfoQueryService;
|
|
||||||
@Inject
|
|
||||||
private SysFileService sysFileService;
|
|
||||||
@Inject
|
|
||||||
private MallCancelPendingOrderEventHandler mallCancelPendingOrderEventHandler;
|
private MallCancelPendingOrderEventHandler mallCancelPendingOrderEventHandler;
|
||||||
@Inject
|
@Inject
|
||||||
private MallSplitSubOrderEventHandler mallSplitSubOrderEventHandler;
|
private MallSplitSubOrderEventHandler mallSplitSubOrderEventHandler;
|
||||||
@@ -103,4 +117,307 @@ public class MallInboundEventService extends AbstractMallBridgeSupport {
|
|||||||
handlerRegistry.put(handler.getType(), handler);
|
handlerRegistry.put(handler.getType(), handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MallInboundResult cancelMainOrder(MallOrderEventDTO dto, boolean paidNotSplit) {
|
||||||
|
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
|
||||||
|
if (StrUtil.isBlank(mainOrderId)) {
|
||||||
|
return MallInboundResult.fail(400, "主订单信息不能为空");
|
||||||
|
}
|
||||||
|
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
|
||||||
|
if (main == null) {
|
||||||
|
return MallInboundResult.fail(404, "主订单不存在");
|
||||||
|
}
|
||||||
|
if (!paidNotSplit && !Integer.valueOf(ORDER_PENDING_PAY).equals(main.getOrderState())) {
|
||||||
|
return MallInboundResult.fail(400, "只能取消未支付主单");
|
||||||
|
}
|
||||||
|
Date now = new Date();
|
||||||
|
Trans.exec((Atom) () -> {
|
||||||
|
main.setOrderState(ORDER_CANCELLED);
|
||||||
|
main.setOrderUpdateTime(now);
|
||||||
|
dao.updateIgnoreNull(main);
|
||||||
|
dao.update(PointsMallOrderSub.class, Chain.make("orderState", ORDER_CANCELLED).add("orderUpdateTime", now),
|
||||||
|
Cnd.where("supplierId", "=", dto.getSupplierId()).and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
|
||||||
|
pointsMallPointsLockService.releaseMain(main.getUserId(), main.getSupplierId(), main.getOrderId());
|
||||||
|
});
|
||||||
|
log.info("积分商城主单取消完成,supplierId={},mainOrderId={},paidNotSplit={}", dto.getSupplierId(), mainOrderId, paidNotSplit);
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MallInboundResult saveOrderSub(MallOrderEventDTO dto) {
|
||||||
|
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "=", dto.getMainOrderId()).and("delFlag", "=", false));
|
||||||
|
if (main == null) {
|
||||||
|
return MallInboundResult.fail(404, "主订单不存在");
|
||||||
|
}
|
||||||
|
List<String> subOrderIds = splitIds(dto.getOrderId());
|
||||||
|
if (mallOrderQueryOutboundService != null) {
|
||||||
|
try {
|
||||||
|
return splitSubOrderByQuery(dto, main, subOrderIds);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("split sub order by query failed, fallback to local split logic, supplierId={}, mainOrderId={}, orderId={}",
|
||||||
|
dto.getSupplierId(), dto.getMainOrderId(), dto.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (subOrderIds.isEmpty()) {
|
||||||
|
return MallInboundResult.fail(400, "子订单信息不能为空");
|
||||||
|
}
|
||||||
|
List<OrderProInfoDTO> products = StrUtil.isBlank(main.getExtJson()) || "null".equalsIgnoreCase(main.getExtJson())
|
||||||
|
? Collections.emptyList()
|
||||||
|
: JSONUtil.toList(main.getExtJson(), OrderProInfoDTO.class);
|
||||||
|
List<PointsMallOrderSub> subLocks = new ArrayList<>();
|
||||||
|
Trans.exec((Atom) () -> {
|
||||||
|
for (String subOrderId : subOrderIds) {
|
||||||
|
PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("orderId", "=", subOrderId)
|
||||||
|
.and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
||||||
|
if (sub == null) {
|
||||||
|
sub = toSub(main, subOrderId);
|
||||||
|
sub.setOrderState(ORDER_IN_PROGRESS);
|
||||||
|
dao.insert(sub);
|
||||||
|
insertProducts(subOrderId, products);
|
||||||
|
} else {
|
||||||
|
sub.setOrderState(ORDER_IN_PROGRESS);
|
||||||
|
sub.setOrderUpdateTime(new Date());
|
||||||
|
dao.updateIgnoreNull(sub);
|
||||||
|
}
|
||||||
|
subLocks.add(sub);
|
||||||
|
}
|
||||||
|
pointsMallPointsLockService.createSubLocks(main, subLocks);
|
||||||
|
});
|
||||||
|
log.info("积分商城拆单完成,supplierId={},mainOrderId={},subOrderCount={}", dto.getSupplierId(), dto.getMainOrderId(), subOrderIds.size());
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MallInboundResult splitSubOrderByQuery(MallOrderEventDTO dto, PointsMallOrderMain main, List<String> subOrderIds) {
|
||||||
|
log.info("9.2.1 生成订单信息推送-订单状态为:2(拆单子单)开始执行:{}", dto);
|
||||||
|
if (subOrderIds.isEmpty()) {
|
||||||
|
return MallInboundResult.fail(400, "缺少拆单信息");
|
||||||
|
}
|
||||||
|
log.info("9.2.1 生成订单信息推送-订单状态为:2(拆单子单)调用外部服务获取子单信息:{}", dto);
|
||||||
|
List<OrderInfoDTO> orderInfoList;
|
||||||
|
try {
|
||||||
|
orderInfoList = getOrderInfoList(dto);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("9.2.1 生成订单信息推送-订单状态为:2(拆单子单),调用9.2.2获取订单详情接口异常:{}", e.getMessage(), e);
|
||||||
|
return MallInboundResult.fail(-1, "调用9.2.2获取订单详情接口异常,异常订单:" + subOrderIds);
|
||||||
|
}
|
||||||
|
if (orderInfoList == null || orderInfoList.isEmpty()) {
|
||||||
|
return MallInboundResult.fail(404, "子单不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PointsMallOrderSub> subLocks = new ArrayList<>();
|
||||||
|
Trans.exec((Atom) () -> {
|
||||||
|
for (OrderInfoDTO info : orderInfoList) {
|
||||||
|
PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("orderId", "=", info.getOrderId())
|
||||||
|
.and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
||||||
|
if (sub == null) {
|
||||||
|
sub = toSub(main, info);
|
||||||
|
sub.setOrderState(ORDER_IN_PROGRESS);
|
||||||
|
dao.insert(sub);
|
||||||
|
insertProducts(info.getOrderId(), info.getOrderProInfos() == null ? Collections.emptyList() : info.getOrderProInfos());
|
||||||
|
} else {
|
||||||
|
log.info("9.2.1 生成订单信息推送-订单状态为:2(拆单子单)子单已存在:{}", info);
|
||||||
|
sub.setOrderState(ORDER_IN_PROGRESS);
|
||||||
|
sub.setOrderUpdateTime(new Date());
|
||||||
|
dao.updateIgnoreNull(sub);
|
||||||
|
}
|
||||||
|
subLocks.add(sub);
|
||||||
|
}
|
||||||
|
pointsMallPointsLockService.createSubLocks(main, subLocks);
|
||||||
|
});
|
||||||
|
log.info("9.2.1 生成订单信息推送-订单状态为:2(拆单子单)结束,supplierId={},mainOrderId={},subOrderCount={}",
|
||||||
|
dto.getSupplierId(), dto.getMainOrderId(), orderInfoList.size());
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<OrderInfoDTO> getOrderInfoList(MallOrderEventDTO dto) {
|
||||||
|
MallOrderQueryDTO queryDTO = new MallOrderQueryDTO();
|
||||||
|
queryDTO.setSupplierId(dto.getSupplierId());
|
||||||
|
queryDTO.setOrderId(dto.getOrderId());
|
||||||
|
queryDTO.setOrderType(dto.getOrderType());
|
||||||
|
MallOutboundResult result = mallOrderQueryOutboundService.orderQuery(queryDTO);
|
||||||
|
if (result == null || result.getResultCode() != 0) {
|
||||||
|
throw new RuntimeException(result == null ? "获取订单详情返回为空" : result.getMessage());
|
||||||
|
}
|
||||||
|
return result.getOrderInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointsMallOrderSub toSub(PointsMallOrderMain main, OrderInfoDTO info) {
|
||||||
|
PointsMallOrderSub sub = toSub(main, info.getOrderId());
|
||||||
|
sub.setOrderNumberId(info.getOrderNumberId());
|
||||||
|
sub.setAplName(StrUtil.blankToDefault(info.getAplName(), main.getAplName()));
|
||||||
|
sub.setOrderCreateTime(parseDate(info.getCreateTime()));
|
||||||
|
sub.setOrderUpdateTime(parseDate(info.getUpdateTime()));
|
||||||
|
sub.setDeliveryTime(parseDate(info.getDeliveryTime()));
|
||||||
|
sub.setOrderFinishTime(parseDate(info.getOrderFinishTime()));
|
||||||
|
sub.setOrderCompleteTime(parseDate(info.getCompleteTime()));
|
||||||
|
sub.setDeliveryStatus(parseInteger(info.getDeliveryStatus()));
|
||||||
|
sub.setFreightCost(nvl(info.getFreightCost()));
|
||||||
|
sub.setWPayOrAPayFreightCost(nvl(info.getWPayOrAPayFreightCost()));
|
||||||
|
sub.setRefund(nvl(info.getRefund()));
|
||||||
|
sub.setWPayOrAPayRefund(nvl(info.getWPayOrAPayRefund()));
|
||||||
|
sub.setLogisticsOrderId(info.getLogisticsOrderId());
|
||||||
|
sub.setCrrgBsnNm(info.getCrrgBsnNm());
|
||||||
|
sub.setTotalPrice(nvl(info.getTotalPrice()));
|
||||||
|
sub.setWPayOrAPay(nvl(info.getWPayOrAPay()));
|
||||||
|
sub.setPointsPrice(nvl(info.getPointsPrice()));
|
||||||
|
sub.setInvoiceCode(info.getInvoiceCode());
|
||||||
|
sub.setExtJson(JSONUtil.toJsonStr(info.getOrderProInfos() == null ? Collections.emptyList() : info.getOrderProInfos()));
|
||||||
|
sub.setReconciliationStatus(0);
|
||||||
|
sub.setInvoiceStatus(0);
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新子单状态。
|
||||||
|
*
|
||||||
|
* <p>订单类型为:6(确认收货)时,供应商侧“确认收货”对应 zhgh/callP 侧“已妥投(4)”,
|
||||||
|
* 需重新调用 9.2.2 获取订单详情接口,补充确认收货时间、发货时间、商品信息等字段。</p>
|
||||||
|
*
|
||||||
|
* @param dto 请求参数
|
||||||
|
* @param statusEnum zhgh/callP 侧订单状态枚举
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
public MallInboundResult updateSubOrderStatus(MallOrderEventDTO dto, MallOrderStatusEnum statusEnum) {
|
||||||
|
Integer state = statusEnum.getCode();
|
||||||
|
PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "=", dto.getOrderId()).and("delFlag", "=", false));
|
||||||
|
if (sub == null) {
|
||||||
|
return MallInboundResult.fail(404, "订单不存在");
|
||||||
|
}
|
||||||
|
if (Integer.valueOf(state).equals(sub.getOrderState())) {
|
||||||
|
log.info("积分商城子单状态已是目标状态,跳过重复处理,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
Trans.exec((Atom) () -> {
|
||||||
|
if (statusEnum == MallOrderStatusEnum.RECEIVED) {
|
||||||
|
fillReceivedSubOrder(dto, sub);
|
||||||
|
}
|
||||||
|
sub.setOrderState(state);
|
||||||
|
if (statusEnum != MallOrderStatusEnum.RECEIVED || sub.getOrderUpdateTime() == null) {
|
||||||
|
sub.setOrderUpdateTime(new Date());
|
||||||
|
}
|
||||||
|
if (statusEnum == MallOrderStatusEnum.RECEIVED && sub.getOrderFinishTime() == null) {
|
||||||
|
sub.setOrderFinishTime(new Date());
|
||||||
|
}
|
||||||
|
if (statusEnum == MallOrderStatusEnum.COMPLETED) {
|
||||||
|
sub.setOrderCompleteTime(new Date());
|
||||||
|
}
|
||||||
|
dao.updateIgnoreNull(sub);
|
||||||
|
if (statusEnum == MallOrderStatusEnum.CANCELLED || statusEnum == MallOrderStatusEnum.REFUNDED || statusEnum == MallOrderStatusEnum.ABOLISH) {
|
||||||
|
pointsMallPointsLockService.releaseOrReturnPoints(sub, state, nvl(sub.getRefund(), BigDecimal.ZERO));
|
||||||
|
}
|
||||||
|
if (statusEnum == MallOrderStatusEnum.COMPLETED) {
|
||||||
|
pointsMallPointsLockService.deductCompletedSub(sub);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("积分商城子单状态更新完成,supplierId={},orderId={},state={}", dto.getSupplierId(), dto.getOrderId(), state);
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单类型为:6(确认收货)时,调用 9.2.2 获取订单详情接口,补充子单妥投相关信息。
|
||||||
|
*
|
||||||
|
* <p>供应商侧确认收货只代表电商处已收货,对 zhgh/callP 侧应更新为已妥投(4),
|
||||||
|
* 等待 callP 用户侧确认收货后才进入已完成(5)。</p>
|
||||||
|
*/
|
||||||
|
private void fillReceivedSubOrder(MallOrderEventDTO dto, PointsMallOrderSub sub) {
|
||||||
|
if (mallOrderQueryOutboundService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MallOrderQueryDTO queryDTO = new MallOrderQueryDTO();
|
||||||
|
queryDTO.setSupplierId(dto.getSupplierId());
|
||||||
|
queryDTO.setOrderId(dto.getOrderId());
|
||||||
|
queryDTO.setOrderType(2);
|
||||||
|
log.info("订单类型为:6(确认收货)时,调用9.2.2获取订单详情接口:{}", queryDTO);
|
||||||
|
try {
|
||||||
|
MallOutboundResult result = mallOrderQueryOutboundService.queryOrderInfo(queryDTO);
|
||||||
|
if (result == null || result.getResultCode() != 0 || result.getOrderInfo() == null || result.getOrderInfo().isEmpty()) {
|
||||||
|
log.error("订单类型为:6(确认收货)时,调用9.2.2 获取订单详情失败:{},{}", queryDTO, result == null ? null : result.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OrderInfoDTO orderInfo = result.getOrderInfo().get(0);
|
||||||
|
sub.setOrderCreateTime(parseDate(orderInfo.getCreateTime()));
|
||||||
|
sub.setOrderUpdateTime(parseDate(orderInfo.getUpdateTime()));
|
||||||
|
sub.setOrderFinishTime(parseDate(orderInfo.getOrderFinishTime()));
|
||||||
|
sub.setDeliveryTime(parseDate(orderInfo.getDeliveryTime()));
|
||||||
|
sub.setDeliveryStatus(parseInteger(orderInfo.getDeliveryStatus()));
|
||||||
|
if (orderInfo.getOrderProInfos() != null) {
|
||||||
|
sub.setExtJson(JSONUtil.toJsonStr(orderInfo.getOrderProInfos()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("订单类型为:6(确认收货)时,调用9.2.2 获取订单详情异常:{},{}", queryDTO, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MallInboundResult updateDeliveryStatus(MallOrderEventDTO dto) {
|
||||||
|
if (StrUtil.isBlank(dto.getSupplierId()) || StrUtil.isBlank(dto.getOrderId())) {
|
||||||
|
return MallInboundResult.fail(400, "供应商或订单不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> orderIds = splitIds(dto.getOrderId());
|
||||||
|
if (orderIds.isEmpty()) {
|
||||||
|
return MallInboundResult.fail(400, "订单信息不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
Date deliveryTime = parseDate(dto.getDeliveryTime());
|
||||||
|
if (deliveryTime == null) {
|
||||||
|
deliveryTime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cnd subCnd = Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "in", orderIds)
|
||||||
|
.and("delFlag", "=", false);
|
||||||
|
if (StrUtil.isNotBlank(dto.getUserId())) {
|
||||||
|
subCnd.and("userId", "=", dto.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PointsMallOrderSub> subs = dao.query(PointsMallOrderSub.class, subCnd);
|
||||||
|
if (subs.isEmpty()) {
|
||||||
|
return MallInboundResult.fail(404, "订单不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
Date finalDeliveryTime = deliveryTime;
|
||||||
|
Integer deliveredStatus = 1;
|
||||||
|
Trans.exec((Atom) () -> {
|
||||||
|
Chain subChain = Chain.make("deliveryStatus", deliveredStatus)
|
||||||
|
.add("deliveryTime", finalDeliveryTime);
|
||||||
|
if (StrUtil.isNotBlank(dto.getLogisticsOrderId())) {
|
||||||
|
subChain.add("logisticsOrderId", dto.getLogisticsOrderId());
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(dto.getCrrgBsnNm())) {
|
||||||
|
subChain.add("crrgBsnNm", dto.getCrrgBsnNm());
|
||||||
|
}
|
||||||
|
dao.update(PointsMallOrderSub.class, subChain, subCnd);
|
||||||
|
|
||||||
|
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), subs.get(0).getMainOrderId());
|
||||||
|
if (StrUtil.isNotBlank(mainOrderId)) {
|
||||||
|
Chain mainChain = Chain.make("deliveryStatus", String.valueOf(deliveredStatus))
|
||||||
|
.add("deliveryTime", finalDeliveryTime);
|
||||||
|
if (StrUtil.isNotBlank(dto.getLogisticsOrderId())) {
|
||||||
|
mainChain.add("logisticsOrderId", dto.getLogisticsOrderId());
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(dto.getCrrgBsnNm())) {
|
||||||
|
mainChain.add("crrgBsnNm", dto.getCrrgBsnNm());
|
||||||
|
}
|
||||||
|
dao.update(PointsMallOrderMain.class, mainChain, Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info("供应商已发货事件处理完成,supplierId={},mainOrderId={},orderIds={},deliveryStatus={}",
|
||||||
|
dto.getSupplierId(), dto.getMainOrderId(), orderIds, deliveredStatus);
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MallInboundResult invoiceInfo(MallOrderEventDTO dto) {
|
||||||
|
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
|
||||||
|
if (StrUtil.isBlank(mainOrderId)) {
|
||||||
|
return MallInboundResult.fail(400, "主订单信息不能为空");
|
||||||
|
}
|
||||||
|
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
|
||||||
|
log.info("积分商城发票通知状态更新完成,supplierId={},mainOrderId={}", dto.getSupplierId(), mainOrderId);
|
||||||
|
return MallInboundResult.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -2,7 +2,6 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPendingOrderDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPendingOrderDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
||||||
@@ -33,17 +32,13 @@ public class MallInboundPendingOrderService extends AbstractMallBridgeSupport {
|
|||||||
if (dto.getOrderInfo() == null || StrUtil.isBlank(dto.getOrderInfo().getOrderId())) {
|
if (dto.getOrderInfo() == null || StrUtil.isBlank(dto.getOrderInfo().getOrderId())) {
|
||||||
return MallInboundResult.fail(400, "订单信息不能为空");
|
return MallInboundResult.fail(400, "订单信息不能为空");
|
||||||
}
|
}
|
||||||
Sys_user user = fetchUser(dto.getUserId());
|
|
||||||
if (user == null) {
|
|
||||||
return MallInboundResult.fail(400, "用户虚拟ID未配置或不存在");
|
|
||||||
}
|
|
||||||
log.info("积分商城接收待支付订单开始,supplierId={},orderId={}", dto.getSupplierId(), dto.getOrderInfo().getOrderId());
|
log.info("积分商城接收待支付订单开始,supplierId={},orderId={}", dto.getSupplierId(), dto.getOrderInfo().getOrderId());
|
||||||
if (dao.count(PointsMallOrderMain.class, Cnd.where("orderId", "=", dto.getOrderInfo().getOrderId())
|
if (dao.count(PointsMallOrderMain.class, Cnd.where("orderId", "=", dto.getOrderInfo().getOrderId())
|
||||||
.and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false)) > 0) {
|
.and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false)) > 0) {
|
||||||
return MallInboundResult.fail(-1, "订单已存在");
|
return MallInboundResult.fail(-1, "订单已存在");
|
||||||
}
|
}
|
||||||
Trans.exec((Atom) () -> {
|
Trans.exec((Atom) () -> {
|
||||||
PointsMallOrderMain main = toMain(dto.getSupplierId(), user.getId(), dto.getOrderInfo(), ORDER_PENDING_PAY);
|
PointsMallOrderMain main = toMain(dto.getSupplierId(), dto.getUserId(), dto.getOrderInfo(), ORDER_PENDING_PAY);
|
||||||
dao.insert(main);
|
dao.insert(main);
|
||||||
|
|
||||||
// 新增主单历史记录
|
// 新增主单历史记录
|
||||||
|
|||||||
+3
-18
@@ -1,13 +1,9 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPointQueryDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPointQueryDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService;
|
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
@@ -15,28 +11,17 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
* 商城桥接积分查询服务。
|
* 商城桥接积分查询服务。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean
|
||||||
public class MallInboundPointsQueryService extends AbstractMallBridgeSupport {
|
public class MallInboundPointsQueryService {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PointsMallUserPointsService pointsMallUserPointsService;
|
private PointsMallUserPointsService pointsMallUserPointsService;
|
||||||
|
|
||||||
public MallInboundPointsQueryService(Dao dao) {
|
|
||||||
super(dao);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户可用积分。
|
* 查询用户可用积分。
|
||||||
*/
|
*/
|
||||||
public MallInboundPointsResult queryPoints(MallPointQueryDTO dto) {
|
public MallInboundPointsResult queryPoints(MallPointQueryDTO dto) {
|
||||||
log.info("积分商城查询用户积分,supplierId={},userId={}", dto == null ? null : dto.getSupplierId(), dto == null ? null : dto.getUserId());
|
log.info("积分商城查询用户积分,supplierId={},userId={}", dto == null ? null : dto.getSupplierId(), dto == null ? null : dto.getUserId());
|
||||||
if (dto == null || StrUtil.isBlank(dto.getUserId())) {
|
return MallInboundPointsResult.success(pointsMallUserPointsService.availablePoints(dto.getUserId()));
|
||||||
return MallInboundPointsResult.fail(400, "用户虚拟ID不能为空");
|
|
||||||
}
|
|
||||||
Sys_user user = fetchUser(dto.getUserId());
|
|
||||||
if (user == null) {
|
|
||||||
return MallInboundPointsResult.fail(400, "用户虚拟ID未配置或不存在");
|
|
||||||
}
|
|
||||||
return MallInboundPointsResult.success(pointsMallUserPointsService.availablePoints(user.getId()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderMessageDTO;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPurchaseResultDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPurchaseResultDTO;
|
||||||
@@ -59,7 +58,7 @@ public class MallInboundPurchaseResultService {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// callP消息推送
|
// callP消息推送
|
||||||
mallCallPMessagePushService.pushMessageToGlobal("11111111", BeanUtil.copyProperties(orderMain, MallOrderMessageDTO.class));
|
mallCallPMessagePushService.pushMessageToGlobal(orderMain);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("9.2.14 支付结果通知接口,callP消息推送:{},{}", dto, e.getMessage());
|
log.error("9.2.14 支付结果通知接口,callP消息推送:{},{}", dto, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-48
@@ -1,22 +1,24 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
||||||
|
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeResponseUtil;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallInvoiceApplyDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallInvoiceApplyDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Chain;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.trans.Atom;
|
||||||
|
import org.nutz.trans.Trans;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商城桥接开票申请出站服务。
|
* 商城桥接开票申请出站服务。
|
||||||
@@ -25,61 +27,73 @@ import java.util.HashMap;
|
|||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class MallInvoiceApplyOutboundService extends AbstractMallBridgeSupport {
|
public class MallInvoiceApplyOutboundService extends AbstractMallBridgeSupport {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PropertiesProxy conf;
|
|
||||||
|
|
||||||
public MallInvoiceApplyOutboundService(Dao dao) {
|
public MallInvoiceApplyOutboundService(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向供应商发起开票申请。
|
* 接收开票申请并保存开票记录。
|
||||||
*/
|
*/
|
||||||
public MallOutboundResult applyInvoice(MallInvoiceApplyDTO dto) {
|
public MallOutboundResult applyInvoice(MallInvoiceApplyDTO dto) {
|
||||||
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId(), dto.getOrderIds())) {
|
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId(), dto.getOrderIds())) {
|
||||||
return MallOutboundResult.fail(400, "开票申请参数不能为空");
|
return MallOutboundResult.fail(400, "开票申请参数不能为空");
|
||||||
}
|
}
|
||||||
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
|
List<String> orderIds = splitIds(dto.getOrderIds());
|
||||||
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
|
log.info("积分商城开票申请开始,supplierId={},settlementId={},orderCount={}", dto.getSupplierId(), dto.getSettlementId(), orderIds.size());
|
||||||
return MallOutboundResult.fail(500, "未配置 BAB7 服务地址");
|
List<PointsMallOrderSub> orders = dao.query(PointsMallOrderSub.class, Cnd.where("supplierId", "=", dto.getSupplierId())
|
||||||
|
.and("orderId", "in", orderIds).and("delFlag", "=", false));
|
||||||
|
if (orders.isEmpty()) {
|
||||||
|
return MallOutboundResult.fail(404, "未找到可开票订单");
|
||||||
}
|
}
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
if (dto.getOrderNum() != null && dto.getOrderNum() != orders.size()) {
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
return MallOutboundResult.fail(400, "订单数量与开票申请不一致");
|
||||||
if (supplier == null) {
|
|
||||||
return MallOutboundResult.fail(404, "未找到对应供应商信息");
|
|
||||||
}
|
}
|
||||||
if (StrUtil.isBlank(supplier.getSupplierApiUrl())) {
|
BigDecimal total = orders.stream().map(PointsMallOrderSub::getTotalPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
return MallOutboundResult.fail(404, "供应商地址未配置");
|
if (dto.getOrderTotalPrice() != null && total.compareTo(dto.getOrderTotalPrice()) != 0) {
|
||||||
|
return MallOutboundResult.fail(400, "订单金额与开票申请不一致");
|
||||||
}
|
}
|
||||||
long timestamp = System.currentTimeMillis();
|
Trans.exec((Atom) () -> saveInvoiceApply(dto, orderIds, total));
|
||||||
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp));
|
log.info("积分商城开票申请完成,supplierId={},settlementId={}", dto.getSupplierId(), dto.getSettlementId());
|
||||||
dto.setTimestamp(timestamp);
|
return MallOutboundResult.success();
|
||||||
|
|
||||||
String keyHex = conf.get("sm4cbc.keyHex", "");
|
|
||||||
String ivHex = conf.get("sm4cbc.ivHex", "");
|
|
||||||
String encrypt;
|
|
||||||
try {
|
|
||||||
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(JSONUtil.toJsonStr(dto), keyHex, ivHex);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("9.2.5 发票开具申请接口请求参数 SM4CBC 加密出错", e);
|
|
||||||
return MallOutboundResult.fail(500, "发票开具申请参数加密失败");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<String, Object> bodyMap = new HashMap<>();
|
private void saveInvoiceApply(MallInvoiceApplyDTO dto, List<String> orderIds, BigDecimal total) {
|
||||||
bodyMap.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/applyForInvoices");
|
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getSettlementId()).and("delFlag", "=", false));
|
||||||
bodyMap.put("BussDealMd", "P");
|
if (main == null) {
|
||||||
bodyMap.put("SroNo", supplier.getSroNo());
|
main = new PointsMallInvoiceMain();
|
||||||
bodyMap.put("RsrvFld1", supplier.getClientId());
|
main.setSettlementId(dto.getSettlementId());
|
||||||
bodyMap.put("AplParmObjct", encrypt);
|
main.setBSuccess(0);
|
||||||
|
main.setSucOrderIds(String.join(",", orderIds));
|
||||||
|
main.setFailOrderIds("");
|
||||||
|
main.setFailMsg("");
|
||||||
|
dao.insert(main);
|
||||||
|
} else {
|
||||||
|
main.setBSuccess(0);
|
||||||
|
main.setSucOrderIds(String.join(",", orderIds));
|
||||||
|
main.setFailOrderIds("");
|
||||||
|
main.setFailMsg("");
|
||||||
|
dao.updateIgnoreNull(main);
|
||||||
|
}
|
||||||
|
|
||||||
String response = HttpUtil.createPost(clientBAB7ServerUrl)
|
PointsMallInvoiceInfo info = new PointsMallInvoiceInfo();
|
||||||
.contentType("application/json;charset=UTF-8")
|
info.setMainId(main.getId());
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
info.setInvoiceId(dto.getSettlementId());
|
||||||
.execute()
|
info.setInvoiceCode(dto.getInvoiceCode());
|
||||||
.body();
|
info.setInvoiceDate(parseDate(dto.getInvoiceDate()));
|
||||||
if (StrUtil.isBlank(response)) {
|
info.setInvoiceNakeAmount(nvl(dto.getInvoiceNakedPrice(), total));
|
||||||
return MallOutboundResult.fail(502, "供应商开票申请无响应");
|
info.setInvoiceTaxAmount(nvl(dto.getInvoiceTaxPrice(), BigDecimal.ZERO));
|
||||||
}
|
info.setInvoiceAmount(total);
|
||||||
return JSONUtil.toBean(MallBridgeResponseUtil.parse(response), MallOutboundResult.class);
|
info.setInvoiceType(Convert.toInt(dto.getInvoiceType(), null));
|
||||||
|
info.setInvoiceAddress(dto.getInvoiceAddress());
|
||||||
|
info.setInvoiceContact(dto.getInvoiceContact());
|
||||||
|
info.setInvoiceContent(dto.getInvoiceContent());
|
||||||
|
info.setInvoiceBank(dto.getBankName());
|
||||||
|
info.setInvoiceAccount(dto.getBankAccount());
|
||||||
|
info.setTaxIdNumber(dto.getInvoiceCode());
|
||||||
|
info.setRemark(dto.getRemark());
|
||||||
|
dao.insert(info);
|
||||||
|
|
||||||
|
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2).add("invoiceCode", dto.getSettlementId()),
|
||||||
|
Cnd.where("supplierId", "=", dto.getSupplierId()).and("orderId", "in", orderIds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-103
@@ -1,26 +1,19 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
|
||||||
import cn.hutool.json.JSONObject;
|
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeResponseUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.GetInvoiceInfoDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.GetInvoiceInfoDTO;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.InvoiceInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.PictureQueryDTO;
|
import java.util.stream.Collectors;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商城桥接发票信息查询服务。
|
* 商城桥接发票信息查询服务。
|
||||||
@@ -29,51 +22,10 @@ import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
|
|||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class MallInvoiceInfoQueryService extends AbstractMallBridgeSupport {
|
public class MallInvoiceInfoQueryService extends AbstractMallBridgeSupport {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PropertiesProxy conf;
|
|
||||||
|
|
||||||
public MallInvoiceInfoQueryService(Dao dao) {
|
public MallInvoiceInfoQueryService(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MallPictureOutboundResult queryInvoiceFiles(String supplierId, String settlementId, List<String> fileIds) {
|
|
||||||
return queryFiles(supplierId, settlementId, "2", fileIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MallPictureOutboundResult queryFiles(String supplierId, String idNumber, String queryType, List<String> fileIds) {
|
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
|
||||||
Cnd.where("supplierId", "=", supplierId).and("delFlag", "=", false));
|
|
||||||
if (supplier == null || StrUtil.isBlank(supplier.getSupplierApiUrl())) {
|
|
||||||
throw new IllegalArgumentException("供应商或供应商接口地址未配置");
|
|
||||||
}
|
|
||||||
String apiUrl = conf.get("spdb.bab7.url", "");
|
|
||||||
if (StrUtil.isBlank(apiUrl)) {
|
|
||||||
throw new IllegalArgumentException("未配置 BAB7 服务地址");
|
|
||||||
}
|
|
||||||
PictureQueryDTO dto = new PictureQueryDTO();
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
dto.setSupplierId(supplierId);
|
|
||||||
dto.setToken(MallBridgeCryptoUtil.generateSign(supplierId, supplier.getClientId(), timestamp));
|
|
||||||
dto.setTimestamp(timestamp);
|
|
||||||
dto.setQueryType(queryType);
|
|
||||||
dto.setIdNumber(idNumber);
|
|
||||||
dto.setFileIdList(fileIds);
|
|
||||||
HashMap<String, Object> body = new HashMap<>();
|
|
||||||
body.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/queryFileBase64Info");
|
|
||||||
body.put("BussDealMd", "P");
|
|
||||||
body.put("SroNo", supplier.getSroNo());
|
|
||||||
body.put("RsrvFld1", supplier.getClientId());
|
|
||||||
body.put("AplParmObjct", MallBridgeCryptoUtil.sm4CbcEncrypt(JSONUtil.toJsonStr(dto),
|
|
||||||
conf.get("sm4cbc.keyHex", ""), conf.get("sm4cbc.ivHex", "")));
|
|
||||||
String response = HttpUtil.createPost(apiUrl).contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(body)).execute().body();
|
|
||||||
JSONObject payload = MallBridgeResponseUtil.parse(response);
|
|
||||||
if (payload.getInt("resultCode", -1) != 0) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.blankToDefault(payload.getStr("message"), "获取供应商文件失败"));
|
|
||||||
}
|
|
||||||
return JSONUtil.toBean(payload, MallPictureOutboundResult.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询指定结算单的发票信息。
|
* 查询指定结算单的发票信息。
|
||||||
*/
|
*/
|
||||||
@@ -81,57 +33,21 @@ public class MallInvoiceInfoQueryService extends AbstractMallBridgeSupport {
|
|||||||
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId())) {
|
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId())) {
|
||||||
throw new IllegalArgumentException("发票查询参数不能为空");
|
throw new IllegalArgumentException("发票查询参数不能为空");
|
||||||
}
|
}
|
||||||
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
|
log.info("积分商城查询发票信息,supplierId={},settlementId={}", dto.getSupplierId(), dto.getSettlementId());
|
||||||
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
|
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getSettlementId())
|
||||||
throw new IllegalArgumentException("未配置 BAB7 服务地址");
|
.and("delFlag", "=", false));
|
||||||
|
if (main == null) {
|
||||||
|
throw new IllegalArgumentException("发票信息不存在");
|
||||||
}
|
}
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
List<InvoiceInfoDTO> invoiceInfos = dao.query(PointsMallInvoiceInfo.class, Cnd.where("mainId", "=", main.getId()).and("delFlag", "=", false))
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
.stream().map(this::toInvoiceInfoDTO).collect(Collectors.toList());
|
||||||
if (supplier == null) {
|
GetInvoiceInfoDTO result = new GetInvoiceInfoDTO();
|
||||||
throw new IllegalArgumentException("未找到对应供应商信息");
|
result.setBSuccess(main.getBSuccess());
|
||||||
}
|
result.setSettlementId(main.getSettlementId());
|
||||||
if (StrUtil.isBlank(supplier.getSupplierApiUrl())) {
|
result.setSucOrderIds(main.getSucOrderIds());
|
||||||
throw new IllegalArgumentException("供应商地址未配置");
|
result.setFailOrderIds(main.getFailOrderIds());
|
||||||
}
|
result.setFailMsg(main.getFailMsg());
|
||||||
|
result.setInvoiceInfos(invoiceInfos);
|
||||||
long timestamp = System.currentTimeMillis();
|
return result;
|
||||||
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp));
|
|
||||||
dto.setTimestamp(timestamp);
|
|
||||||
String encrypt;
|
|
||||||
try {
|
|
||||||
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(
|
|
||||||
JSONUtil.toJsonStr(dto),
|
|
||||||
conf.get("sm4cbc.keyHex", ""),
|
|
||||||
conf.get("sm4cbc.ivHex", "")
|
|
||||||
);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("9.2.10 发票获取接口请求参数 SM4CBC 加密出错", e);
|
|
||||||
throw new IllegalArgumentException("发票获取请求参数加密失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<String, Object> bodyMap = new HashMap<>();
|
|
||||||
bodyMap.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/queryInvoicesInfo");
|
|
||||||
bodyMap.put("BussDealMd", "P");
|
|
||||||
bodyMap.put("SroNo", supplier.getSroNo());
|
|
||||||
bodyMap.put("RsrvFld1", supplier.getClientId());
|
|
||||||
bodyMap.put("AplParmObjct", encrypt);
|
|
||||||
|
|
||||||
String response = HttpUtil.createPost(clientBAB7ServerUrl)
|
|
||||||
.contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
|
||||||
.execute()
|
|
||||||
.body();
|
|
||||||
if (StrUtil.isBlank(response)) {
|
|
||||||
throw new IllegalArgumentException("没有查询到发票信息");
|
|
||||||
}
|
|
||||||
JSONObject responseJson = MallBridgeResponseUtil.parse(response);
|
|
||||||
if (responseJson.getInt("resultCode", -1) != 0) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.blankToDefault(responseJson.getStr("message"), "获取发票信息失败"));
|
|
||||||
}
|
|
||||||
JSONObject invoiceInfo = responseJson.getJSONObject("getInvoiceInfo");
|
|
||||||
if (invoiceInfo == null) {
|
|
||||||
throw new IllegalArgumentException("没有查询到发票信息");
|
|
||||||
}
|
|
||||||
return JSONUtil.toBean(invoiceInfo, GetInvoiceInfoDTO.class);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-27
@@ -2,7 +2,6 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
|||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
|
||||||
@@ -86,31 +85,6 @@ public class MallOrderQueryOutboundService {
|
|||||||
.execute()
|
.execute()
|
||||||
.body();
|
.body();
|
||||||
log.info("9.2.2 获取订单详情调用结束,返回报文:{}", response);
|
log.info("9.2.2 获取订单详情调用结束,返回报文:{}", response);
|
||||||
JSONObject payload = JSONUtil.parseObj(response);
|
return JSONUtil.toBean(response, MallOutboundResult.class);
|
||||||
if (!payload.containsKey("resultCode")) {
|
|
||||||
JSONObject data = payload.getJSONObject("data");
|
|
||||||
JSONObject body = data == null ? null : data.getJSONObject("Body");
|
|
||||||
if (body == null) {
|
|
||||||
return MallOutboundResult.fail(502, "获取订单详情返回报文格式异常");
|
|
||||||
}
|
|
||||||
JSONObject header = body.getJSONObject("RspSvcHeader");
|
|
||||||
if (header == null || !"000000000000".equals(header.getStr("ReturnCode"))) {
|
|
||||||
return MallOutboundResult.fail(502, header == null ? "BAB7返回服务头缺失" :
|
|
||||||
StrUtil.blankToDefault(header.getStr("ReturnMsg"), "BAB7获取订单详情失败"));
|
|
||||||
}
|
|
||||||
JSONObject serviceBody = body.getJSONObject("RspSvcBody");
|
|
||||||
if (serviceBody == null || !"200".equals(serviceBody.getStr("ReturnStCd"))) {
|
|
||||||
return MallOutboundResult.fail(502, "BAB7调用供应商订单详情接口失败");
|
|
||||||
}
|
|
||||||
String content = serviceBody.getStr("ReturnCntnt");
|
|
||||||
if (StrUtil.isBlank(content)) {
|
|
||||||
return MallOutboundResult.fail(502, "供应商订单详情返回内容为空");
|
|
||||||
}
|
|
||||||
payload = JSONUtil.parseObj(content);
|
|
||||||
}
|
|
||||||
if (payload.getInt("resultCode") == null) {
|
|
||||||
return MallOutboundResult.fail(502, "供应商订单详情返回状态缺失");
|
|
||||||
}
|
|
||||||
return JSONUtil.toBean(payload, MallOutboundResult.class);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-185
@@ -1,185 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoByReconciliationDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryReconciliationInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundPageResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对账信息
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@IocBean(args = {"refer:dao"})
|
|
||||||
public class MallReconciliationInfoQueryService {
|
|
||||||
|
|
||||||
private final Dao dao;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PropertiesProxy conf;
|
|
||||||
|
|
||||||
public MallReconciliationInfoQueryService(Dao dao) {
|
|
||||||
this.dao = dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<OrderInfoByReconciliationDTO> queryReconciliationInfo(QueryReconciliationInfoDTO dto) {
|
|
||||||
// 从供应商获取对账订单信息
|
|
||||||
return getOrderInfoFromSupplier(dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<OrderInfoByReconciliationDTO> getOrderInfoFromSupplier(QueryReconciliationInfoDTO dto) {
|
|
||||||
log.info("9.2.4 对账接口执行开始:{}", dto);
|
|
||||||
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
|
|
||||||
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
|
|
||||||
throw new IllegalArgumentException("未配置 BAB7 服务地址");
|
|
||||||
}
|
|
||||||
|
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
|
||||||
if (supplier == null) {
|
|
||||||
log.error("9.2.4 对账接口 未找到对应供应商信息");
|
|
||||||
throw new IllegalArgumentException("未找到对应供应商信息");
|
|
||||||
}
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
// 计算token
|
|
||||||
String token = MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp);
|
|
||||||
dto.setToken(token);
|
|
||||||
dto.setTimestamp(timestamp);
|
|
||||||
// 组装请求报文
|
|
||||||
HashMap<String, Object> bodyMap = buildReqParam(dto, supplier);
|
|
||||||
log.info("9.2.4 通过对接接口从供应商获取对账订单数据:{}", dto);
|
|
||||||
String response = HttpUtil.createPost(clientBAB7ServerUrl)
|
|
||||||
.contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
|
||||||
.execute()
|
|
||||||
.body();
|
|
||||||
log.info("通过对账接口获取对账订单数据,响应结果:{}", response);
|
|
||||||
MallOutboundPageResult mallOutboundPageResult = parseReconciliationResponse(response);
|
|
||||||
if (CollUtil.isEmpty(mallOutboundPageResult.getOrderInfos())) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<OrderInfoByReconciliationDTO> orderInfoList = new ArrayList<>(mallOutboundPageResult.getOrderInfos());
|
|
||||||
// 页码
|
|
||||||
Integer page = dto.getPage();
|
|
||||||
// 总页数
|
|
||||||
Integer totalPage = mallOutboundPageResult.getTotalPage();
|
|
||||||
// 当返回的总页数没有变化,以传入的page来循环拉取
|
|
||||||
while (page < totalPage) {
|
|
||||||
// 循环拉取page页的数据
|
|
||||||
dto.setPage(page + 1);
|
|
||||||
log.info("9.2.4 对账接口-分页循环拉取,入参:{}", dto);
|
|
||||||
bodyMap = buildReqParam(dto, supplier);
|
|
||||||
response = HttpUtil.createPost(clientBAB7ServerUrl)
|
|
||||||
.contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
|
||||||
.execute()
|
|
||||||
.body();
|
|
||||||
mallOutboundPageResult = parseReconciliationResponse(response);
|
|
||||||
log.info("9.2.4 对账接口-分页循环拉取,返回报文:{}", mallOutboundPageResult);
|
|
||||||
if (CollUtil.isEmpty(mallOutboundPageResult.getOrderInfos())) {
|
|
||||||
throw new IllegalArgumentException("供应商对账分页数据为空,页码:" + dto.getPage());
|
|
||||||
}
|
|
||||||
orderInfoList.addAll(mallOutboundPageResult.getOrderInfos());
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("9.2.4 通过对接接口从供应商获取对账订单数据调用结束,返回报文:{}", orderInfoList);
|
|
||||||
return orderInfoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析 BAB7 包装或供应商直接返回的对账报文,并校验查询结果。
|
|
||||||
*/
|
|
||||||
private MallOutboundPageResult parseReconciliationResponse(String response) {
|
|
||||||
if (StrUtil.isBlank(response)) {
|
|
||||||
throw new IllegalArgumentException("获取对账信息返回报文为空");
|
|
||||||
}
|
|
||||||
JSONObject payload = JSONUtil.parseObj(response);
|
|
||||||
if (!payload.containsKey("resultCode")) {
|
|
||||||
JSONObject data = payload.getJSONObject("data");
|
|
||||||
JSONObject body = data == null ? null : data.getJSONObject("Body");
|
|
||||||
if (body == null) {
|
|
||||||
throw new IllegalArgumentException("获取对账信息返回报文格式异常");
|
|
||||||
}
|
|
||||||
JSONObject header = body.getJSONObject("RspSvcHeader");
|
|
||||||
if (header == null || !"000000000000".equals(header.getStr("ReturnCode"))) {
|
|
||||||
throw new IllegalArgumentException(header == null ? "BAB7返回服务头缺失" :
|
|
||||||
StrUtil.blankToDefault(header.getStr("ReturnMsg"), "BAB7获取对账信息失败"));
|
|
||||||
}
|
|
||||||
JSONObject serviceBody = body.getJSONObject("RspSvcBody");
|
|
||||||
if (serviceBody == null || !"200".equals(serviceBody.getStr("ReturnStCd"))) {
|
|
||||||
throw new IllegalArgumentException("BAB7调用供应商对账接口失败");
|
|
||||||
}
|
|
||||||
String content = serviceBody.getStr("ReturnCntnt");
|
|
||||||
if (StrUtil.isBlank(content)) {
|
|
||||||
throw new IllegalArgumentException("供应商对账接口返回内容为空");
|
|
||||||
}
|
|
||||||
payload = JSONUtil.parseObj(content);
|
|
||||||
}
|
|
||||||
Integer resultCode = payload.getInt("resultCode");
|
|
||||||
if (resultCode == null) {
|
|
||||||
throw new IllegalArgumentException("供应商对账接口返回状态缺失");
|
|
||||||
}
|
|
||||||
if (resultCode != 0) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.blankToDefault(payload.getStr("message"), "供应商对账查询失败"));
|
|
||||||
}
|
|
||||||
MallOutboundPageResult result = JSONUtil.toBean(payload, MallOutboundPageResult.class);
|
|
||||||
if (CollUtil.isNotEmpty(result.getOrderInfos()) && (result.getTotalPage() == null || result.getTotalPage() < 1)) {
|
|
||||||
throw new IllegalArgumentException("供应商对账接口返回总页数无效");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组装请求报文
|
|
||||||
*
|
|
||||||
* @param dto 请求参数
|
|
||||||
* @param supplier 供应商信息
|
|
||||||
* @return 对账接口请求入参
|
|
||||||
*/
|
|
||||||
private HashMap<String, Object> buildReqParam(QueryReconciliationInfoDTO dto, PointsMallSupplier supplier) {
|
|
||||||
// 每个供应商的接口地址不一致,后续判断
|
|
||||||
String address4 = supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/queryReconciliationInfo";
|
|
||||||
String bussDealMd = "P";
|
|
||||||
String srvNo = supplier.getSroNo();
|
|
||||||
String clientId = supplier.getClientId();
|
|
||||||
// 参数(此处需要加密)
|
|
||||||
String params = JSONUtil.toJsonStr(dto);
|
|
||||||
log.info("9.2.4 对账接口-请求参数:{}", params);
|
|
||||||
String keyHex = conf.get("sm4cbc.keyHex", "");
|
|
||||||
String ivHex = conf.get("sm4cbc.ivHex", "");
|
|
||||||
String encrypt;
|
|
||||||
try {
|
|
||||||
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(params, keyHex, ivHex);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("9.2.4 对账接口请求参数 SM4CBC 加密出错:{}", params, e);
|
|
||||||
throw new RuntimeException("9.2.4 对账接口请求参数 SM4CBC 加密出错");
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<String, Object> bodyMap = new HashMap<>();
|
|
||||||
bodyMap.put("Address4", address4);
|
|
||||||
bodyMap.put("BussDealMd", bussDealMd);
|
|
||||||
bodyMap.put("SroNo", srvNo);
|
|
||||||
bodyMap.put("RsrvFld1", clientId);
|
|
||||||
bodyMap.put("AplParmObjct", encrypt);
|
|
||||||
|
|
||||||
return bodyMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-70
@@ -1,70 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.ReconciliationResultNoticeDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对账结果通知服务
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@IocBean(args = {"refer:dao"})
|
|
||||||
public class MallReconciliationResultNoticeService {
|
|
||||||
|
|
||||||
private final Dao dao;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PropertiesProxy conf;
|
|
||||||
|
|
||||||
public MallReconciliationResultNoticeService(Dao dao) {
|
|
||||||
this.dao = dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MallInboundResult reconciliationResultNotice(ReconciliationResultNoticeDTO dto) {
|
|
||||||
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
|
|
||||||
String keyHex = conf.get("sm4cbc.keyHex", "");
|
|
||||||
String ivHex = conf.get("sm4cbc.ivHex", "");
|
|
||||||
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
|
|
||||||
throw new IllegalArgumentException("未配置BAB7服务地址");
|
|
||||||
}
|
|
||||||
|
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
|
||||||
if (supplier == null || StrUtil.isBlank(supplier.getSupplierApiUrl())) {
|
|
||||||
throw new IllegalArgumentException("未找到供应商接口地址");
|
|
||||||
}
|
|
||||||
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
dto.setTimestamp(timestamp);
|
|
||||||
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp));
|
|
||||||
String params = JSONUtil.toJsonStr(dto);
|
|
||||||
String encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(params, keyHex, ivHex);
|
|
||||||
|
|
||||||
HashMap<String, Object> bodyMap = new HashMap<>();
|
|
||||||
bodyMap.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/reconciliationResult");
|
|
||||||
bodyMap.put("BussDealMd", "P");
|
|
||||||
bodyMap.put("SroNo", supplier.getSroNo());
|
|
||||||
bodyMap.put("RsrvFld1", supplier.getClientId());
|
|
||||||
bodyMap.put("AplParmObjct", encrypt);
|
|
||||||
|
|
||||||
String response = HttpUtil.createPost(clientBAB7ServerUrl)
|
|
||||||
.contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
|
||||||
.execute()
|
|
||||||
.body();
|
|
||||||
log.info("对账结果通知接口返回报文:{}", response);
|
|
||||||
return JSONUtil.toBean(response, MallInboundResult.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-69
@@ -2,36 +2,25 @@ package com.budwk.app.zhgh.pointsmall.mallbridge.service;
|
|||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.UnReconciledMsgNoticeDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.UnReconciledMsgNoticeDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.trans.Atom;
|
import org.nutz.trans.Atom;
|
||||||
import org.nutz.trans.Trans;
|
import org.nutz.trans.Trans;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对账异常消息通知服务
|
* 商城桥接对账异常通知服务。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class MallUnReconciledMsgNoticeService extends AbstractMallBridgeSupport {
|
public class MallUnReconciledMsgNoticeService extends AbstractMallBridgeSupport {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PropertiesProxy conf;
|
|
||||||
|
|
||||||
public MallUnReconciledMsgNoticeService(Dao dao) {
|
public MallUnReconciledMsgNoticeService(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
@@ -61,61 +50,4 @@ public class MallUnReconciledMsgNoticeService extends AbstractMallBridgeSupport
|
|||||||
log.info("积分商城对账异常通知完成,supplierId={},orderCount={}", dto.getSupplierId(), orderIds.size());
|
log.info("积分商城对账异常通知完成,supplierId={},orderCount={}", dto.getSupplierId(), orderIds.size());
|
||||||
return MallInboundResult.success();
|
return MallInboundResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MallInboundResult unReconciledMsgNotice(UnReconciledMsgNoticeDTO dto) {
|
|
||||||
log.info("9.3.1 对账异常通知接口调用开始:{}", dto);
|
|
||||||
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
|
|
||||||
String keyHex = conf.get("sm4cbc.keyHex", "");
|
|
||||||
String ivHex = conf.get("sm4cbc.ivHex", "");
|
|
||||||
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
|
|
||||||
throw new IllegalArgumentException("未配置BAB7服务地址");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询供应商信息
|
|
||||||
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
|
|
||||||
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
|
|
||||||
if (supplier == null) {
|
|
||||||
log.error("9.3.1 对账异常通知接口 未找到对应供应商信息");
|
|
||||||
throw new IllegalArgumentException("未找到对应供应商信息");
|
|
||||||
}
|
|
||||||
if (StrUtil.isBlank(supplier.getSupplierApiUrl())) {
|
|
||||||
return MallInboundResult.fail(404, "供应商地址未配置");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组装请求地址
|
|
||||||
String address4 = supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/unReconciledMsg";
|
|
||||||
String bussDealMd = "P";
|
|
||||||
String sroNo = supplier.getSroNo();
|
|
||||||
String clientId = supplier.getClientId();
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
dto.setTimestamp(timestamp);
|
|
||||||
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), clientId, timestamp));
|
|
||||||
// 参数加密
|
|
||||||
String params = JSONUtil.toJsonStr(dto);
|
|
||||||
log.info("9.3.1 对账异常通知接口-请求参数:{}", params);
|
|
||||||
String encrypt;
|
|
||||||
try {
|
|
||||||
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(params, keyHex, ivHex);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("9.3.1 对账异常通知接口参数加密出错:{}", params, e);
|
|
||||||
throw new IllegalArgumentException("参数加密失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建请求体
|
|
||||||
HashMap<String, Object> bodyMap = new HashMap<>();
|
|
||||||
bodyMap.put("Address4", address4);
|
|
||||||
bodyMap.put("BussDealMd", bussDealMd);
|
|
||||||
bodyMap.put("SroNo", sroNo);
|
|
||||||
bodyMap.put("RsrvFld1", clientId);
|
|
||||||
bodyMap.put("AplParmObjct", encrypt);
|
|
||||||
|
|
||||||
// 发送请求
|
|
||||||
String response = HttpUtil.createPost(clientBAB7ServerUrl)
|
|
||||||
.contentType("application/json;charset=UTF-8")
|
|
||||||
.body(JSONUtil.toJsonStr(bodyMap))
|
|
||||||
.execute()
|
|
||||||
.body();
|
|
||||||
log.info("9.3.1 对账异常通知接口返回报文:{}", response);
|
|
||||||
return JSONUtil.toBean(response, MallInboundResult.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-122
@@ -34,105 +34,43 @@ import java.util.stream.Collectors;
|
|||||||
* <p>只放通用转换和常量,具体接口业务放在各自服务中。</p>
|
* <p>只放通用转换和常量,具体接口业务放在各自服务中。</p>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMallBridgeSupport {
|
public abstract class AbstractMallBridgeSupport {
|
||||||
/**
|
|
||||||
* 访问令牌有效期,单位为秒(1 小时)。
|
|
||||||
*/
|
|
||||||
protected static final long ACCESS_EXPIRE_SECONDS = 3600;
|
protected static final long ACCESS_EXPIRE_SECONDS = 3600;
|
||||||
/**
|
|
||||||
* 刷新令牌有效期,单位为秒(7 天)。
|
|
||||||
*/
|
|
||||||
protected static final long REFRESH_EXPIRE_SECONDS = 86400L * 7;
|
protected static final long REFRESH_EXPIRE_SECONDS = 86400L * 7;
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单状态:待支付。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_PENDING_PAY = 0;
|
protected static final int ORDER_PENDING_PAY = 0;
|
||||||
/**
|
|
||||||
* 订单状态:已支付。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_FINISH_PAY = 1;
|
protected static final int ORDER_FINISH_PAY = 1;
|
||||||
/**
|
|
||||||
* 订单状态:处理中。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_IN_PROGRESS = 2;
|
protected static final int ORDER_IN_PROGRESS = 2;
|
||||||
/**
|
|
||||||
* 订单状态:已取消。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_CANCELLED = 3;
|
protected static final int ORDER_CANCELLED = 3;
|
||||||
/**
|
|
||||||
* 订单状态:已收货。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_RECEIVED = 4;
|
protected static final int ORDER_RECEIVED = 4;
|
||||||
/**
|
|
||||||
* 订单状态:已完成。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_COMPLETED = 5;
|
protected static final int ORDER_COMPLETED = 5;
|
||||||
/**
|
|
||||||
* 订单状态:退换货。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_EXCHANGE = 6;
|
protected static final int ORDER_EXCHANGE = 6;
|
||||||
/**
|
|
||||||
* 订单状态:已退款。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_REFUNDED = 7;
|
protected static final int ORDER_REFUNDED = 7;
|
||||||
/**
|
|
||||||
* 订单状态:已作废。
|
|
||||||
*/
|
|
||||||
protected static final int ORDER_ABOLISH = 8;
|
protected static final int ORDER_ABOLISH = 8;
|
||||||
|
|
||||||
/**
|
|
||||||
* 供桥接服务查询和保存用户、订单、商品等数据的 DAO。
|
|
||||||
*/
|
|
||||||
protected final Dao dao;
|
protected final Dao dao;
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化桥接公共支撑类,复用业务服务传入的 DAO。
|
|
||||||
*/
|
|
||||||
protected AbstractMallBridgeSupport(Dao dao) {
|
protected AbstractMallBridgeSupport(Dao dao) {
|
||||||
this.dao = dao;
|
this.dao = dao;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查订单事件及供应商、订单、主订单、用户标识是否齐全;不校验对应数据是否存在。
|
|
||||||
*/
|
|
||||||
protected boolean hasRequiredOrderEventFields(MallOrderEventDTO dto) {
|
protected boolean hasRequiredOrderEventFields(MallOrderEventDTO dto) {
|
||||||
return dto != null && !StrUtil.hasBlank(dto.getSupplierId(), dto.getOrderId(), dto.getMainOrderId(), dto.getUserId());
|
return dto != null && !StrUtil.hasBlank(dto.getSupplierId(), dto.getOrderId(), dto.getMainOrderId(), dto.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected Sys_user fetchUser(String userId) {
|
||||||
* 根据对外用户虚拟 ID 查询未禁用、未删除的系统用户。
|
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", userId).and("disabled", "=", false).and("delFlag", "=", false));
|
||||||
*
|
if (user != null) {
|
||||||
* @param virtualId 供应商接口传入的用户虚拟 ID,不是系统用户主键
|
return user;
|
||||||
* @return 符合条件的用户;虚拟 ID 为空或用户不存在时返回 null
|
|
||||||
*/
|
|
||||||
protected Sys_user fetchUser(String virtualId) {
|
|
||||||
if (StrUtil.isBlank(virtualId)) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return dao.fetch(Sys_user.class, Cnd.where("virtual_id", "=", virtualId)
|
return dao.fetch(Sys_user.class, Cnd.where("loginname", "=", userId).and("disabled", "=", false).and("delFlag", "=", false));
|
||||||
.and("disabled", "=", false).and("delFlag", "=", false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将退换货事件和详情转换为退换货记录,并从原子单补充商品图片及文件信息。
|
|
||||||
*
|
|
||||||
* @param dto 订单事件,其中 userId 为用户虚拟 ID,保存时转换为系统用户主键
|
|
||||||
* @param orderInfo 供应商返回的退换货单详情
|
|
||||||
* @param sub 原子单,提供商品扩展信息
|
|
||||||
* @param orderStatus 待保存的退换货订单状态
|
|
||||||
* @return 尚未入库的退换货记录
|
|
||||||
* @throws IllegalArgumentException 虚拟 ID 对应的有效用户不存在时抛出
|
|
||||||
*/
|
|
||||||
protected PointsMallOrderExchange toExchange(MallOrderEventDTO dto, OrderInfoDTO orderInfo, PointsMallOrderSub sub, Integer orderStatus) {
|
protected PointsMallOrderExchange toExchange(MallOrderEventDTO dto, OrderInfoDTO orderInfo, PointsMallOrderSub sub, Integer orderStatus) {
|
||||||
Sys_user user = fetchUser(dto.getUserId());
|
|
||||||
if (user == null) {
|
|
||||||
throw new IllegalArgumentException("用户虚拟ID未配置或不存在");
|
|
||||||
}
|
|
||||||
PointsMallOrderExchange exchange = new PointsMallOrderExchange();
|
PointsMallOrderExchange exchange = new PointsMallOrderExchange();
|
||||||
exchange.setOrderMainId(dto.getMainOrderId());
|
exchange.setOrderMainId(dto.getMainOrderId());
|
||||||
exchange.setOrderId(dto.getOrderId());
|
exchange.setOrderId(dto.getOrderId());
|
||||||
exchange.setSupplierId(dto.getSupplierId());
|
exchange.setSupplierId(dto.getSupplierId());
|
||||||
exchange.setUserId(user.getId());
|
exchange.setUserId(dto.getUserId());
|
||||||
exchange.setAplName(orderInfo.getAplName());
|
exchange.setAplName(orderInfo.getAplName());
|
||||||
exchange.setOrderCreateTime(parseDate(orderInfo.getCreateTime()));
|
exchange.setOrderCreateTime(parseDate(orderInfo.getCreateTime()));
|
||||||
exchange.setOrderUpdateTime(parseDate(orderInfo.getUpdateTime()));
|
exchange.setOrderUpdateTime(parseDate(orderInfo.getUpdateTime()));
|
||||||
@@ -152,9 +90,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return exchange;
|
return exchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按 SKU 将原子单的图片及文件信息覆盖到传入商品列表中;原子单重复 SKU 取首项,传入列表为空时返回空列表。
|
|
||||||
*/
|
|
||||||
protected List<OrderProInfoDTO> mergeProductInfo(List<OrderProInfoDTO> products, String subExtJson) {
|
protected List<OrderProInfoDTO> mergeProductInfo(List<OrderProInfoDTO> products, String subExtJson) {
|
||||||
if (products == null || products.isEmpty()) {
|
if (products == null || products.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -176,15 +111,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return products;
|
return products;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将供应商订单详情转换为主订单,金额为空时按零处理,现金支付标记初始化为 0。
|
|
||||||
*
|
|
||||||
* @param supplierId 供应商标识
|
|
||||||
* @param userId 已由虚拟 ID 查得的系统用户主键
|
|
||||||
* @param orderInfo 供应商返回的订单详情
|
|
||||||
* @param state 主订单状态
|
|
||||||
* @return 尚未入库的主订单
|
|
||||||
*/
|
|
||||||
protected PointsMallOrderMain toMain(String supplierId, String userId, OrderInfoDTO orderInfo, Integer state) {
|
protected PointsMallOrderMain toMain(String supplierId, String userId, OrderInfoDTO orderInfo, Integer state) {
|
||||||
PointsMallOrderMain main = new PointsMallOrderMain();
|
PointsMallOrderMain main = new PointsMallOrderMain();
|
||||||
main.setOrderId(orderInfo.getOrderId());
|
main.setOrderId(orderInfo.getOrderId());
|
||||||
@@ -212,9 +138,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return main;
|
return main;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从主订单复制信息生成子订单;子订单号为空时使用主订单号,更新时间取当前时间,对账和发票状态初始化为 0。
|
|
||||||
*/
|
|
||||||
protected PointsMallOrderSub toSub(PointsMallOrderMain main, String subOrderId) {
|
protected PointsMallOrderSub toSub(PointsMallOrderMain main, String subOrderId) {
|
||||||
PointsMallOrderSub sub = new PointsMallOrderSub();
|
PointsMallOrderSub sub = new PointsMallOrderSub();
|
||||||
sub.setOrderId(StrUtil.blankToDefault(subOrderId, main.getOrderId()));
|
sub.setOrderId(StrUtil.blankToDefault(subOrderId, main.getOrderId()));
|
||||||
@@ -244,9 +167,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将商品逐条保存到指定子订单,仅保存图片列表中的首张图片;商品列表为 null 时不处理。
|
|
||||||
*/
|
|
||||||
protected void insertProducts(String orderSubId, List<OrderProInfoDTO> products) {
|
protected void insertProducts(String orderSubId, List<OrderProInfoDTO> products) {
|
||||||
if (products == null) {
|
if (products == null) {
|
||||||
return;
|
return;
|
||||||
@@ -264,9 +184,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将查询记录转换为对外订单详情,统一日期和金额格式,并读取订单商品信息。
|
|
||||||
*/
|
|
||||||
protected OrderInfoDTO toOrderInfo(Record record) {
|
protected OrderInfoDTO toOrderInfo(Record record) {
|
||||||
OrderInfoDTO dto = new OrderInfoDTO();
|
OrderInfoDTO dto = new OrderInfoDTO();
|
||||||
dto.setOrderId(record.getString("orderId"));
|
dto.setOrderId(record.getString("orderId"));
|
||||||
@@ -294,9 +211,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 优先读取订单下未删除的子单商品;无商品记录时从 extJson 解析,扩展信息为空或为 null 字符串时返回空列表。
|
|
||||||
*/
|
|
||||||
protected List<OrderProInfoDTO> readProducts(String orderId, String extJson) {
|
protected List<OrderProInfoDTO> readProducts(String orderId, String extJson) {
|
||||||
List<PointsMallOrderSubProduct> products = dao.query(PointsMallOrderSubProduct.class, Cnd.where("orderSubId", "=", orderId).and("delFlag", "=", false));
|
List<PointsMallOrderSubProduct> products = dao.query(PointsMallOrderSubProduct.class, Cnd.where("orderSubId", "=", orderId).and("delFlag", "=", false));
|
||||||
if (!products.isEmpty()) {
|
if (!products.isEmpty()) {
|
||||||
@@ -308,9 +222,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return JSONUtil.toList(extJson, OrderProInfoDTO.class);
|
return JSONUtil.toList(extJson, OrderProInfoDTO.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将子单商品转换为对外商品信息,单张图片包装为列表,并以 SKU 和图片地址填充文件标识及路径。
|
|
||||||
*/
|
|
||||||
protected OrderProInfoDTO toProductDTO(PointsMallOrderSubProduct product) {
|
protected OrderProInfoDTO toProductDTO(PointsMallOrderSubProduct product) {
|
||||||
OrderProInfoDTO dto = new OrderProInfoDTO();
|
OrderProInfoDTO dto = new OrderProInfoDTO();
|
||||||
dto.setSku(product.getSku());
|
dto.setSku(product.getSku());
|
||||||
@@ -324,9 +235,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将发票记录转换为对外发票信息,并将开票时间转换为本地日期。
|
|
||||||
*/
|
|
||||||
protected InvoiceInfoDTO toInvoiceInfoDTO(PointsMallInvoiceInfo info) {
|
protected InvoiceInfoDTO toInvoiceInfoDTO(PointsMallInvoiceInfo info) {
|
||||||
InvoiceInfoDTO dto = new InvoiceInfoDTO();
|
InvoiceInfoDTO dto = new InvoiceInfoDTO();
|
||||||
dto.setInvoiceId(info.getInvoiceId());
|
dto.setInvoiceId(info.getInvoiceId());
|
||||||
@@ -345,9 +253,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析日期字符串,将日期时间分隔符 T 替换为空格;空白值返回 null,非法日期由日期工具抛出异常。
|
|
||||||
*/
|
|
||||||
protected Date parseDate(String value) {
|
protected Date parseDate(String value) {
|
||||||
if (StrUtil.isBlank(value)) {
|
if (StrUtil.isBlank(value)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -355,9 +260,6 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return DateUtil.parse(value.replace("T", " "));
|
return DateUtil.parse(value.replace("T", " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将日期值统一格式化为 yyyy-MM-dd HH:mm:ss;null 值返回 null。
|
|
||||||
*/
|
|
||||||
protected String formatDate(Object value) {
|
protected String formatDate(Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -365,16 +267,10 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
return DateUtil.format(Convert.toDate(value), "yyyy-MM-dd HH:mm:ss");
|
return DateUtil.format(Convert.toDate(value), "yyyy-MM-dd HH:mm:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用系统默认时区将时间转换为日期;null 值返回 null。
|
|
||||||
*/
|
|
||||||
protected LocalDate toLocalDate(Date date) {
|
protected LocalDate toLocalDate(Date date) {
|
||||||
return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 拆分逗号分隔的标识,去除首尾空白、空项和重复项,保留首次出现的顺序;空白值返回空列表。
|
|
||||||
*/
|
|
||||||
protected List<String> splitIds(String value) {
|
protected List<String> splitIds(String value) {
|
||||||
if (StrUtil.isBlank(value)) {
|
if (StrUtil.isBlank(value)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@@ -386,30 +282,18 @@ public abstract class AbstractMallBridgeSupport {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 金额为 null 时返回零,否则保留原值。
|
|
||||||
*/
|
|
||||||
protected BigDecimal nvl(BigDecimal value) {
|
protected BigDecimal nvl(BigDecimal value) {
|
||||||
return value == null ? BigDecimal.ZERO : value;
|
return value == null ? BigDecimal.ZERO : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 金额为 null 时返回指定默认值,否则保留原值。
|
|
||||||
*/
|
|
||||||
protected BigDecimal nvl(BigDecimal value, BigDecimal defaultValue) {
|
protected BigDecimal nvl(BigDecimal value, BigDecimal defaultValue) {
|
||||||
return value == null ? defaultValue : value;
|
return value == null ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转换为金额,无法转换或值为 null 时使用零作为默认值。
|
|
||||||
*/
|
|
||||||
protected BigDecimal decimal(Object value) {
|
protected BigDecimal decimal(Object value) {
|
||||||
return Convert.toBigDecimal(value, BigDecimal.ZERO);
|
return Convert.toBigDecimal(value, BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串转换为整数;空白值或无法转换的值返回 null。
|
|
||||||
*/
|
|
||||||
protected Integer parseInteger(String value) {
|
protected Integer parseInteger(String value) {
|
||||||
if (StrUtil.isBlank(value)) {
|
if (StrUtil.isBlank(value)) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.mallbridge.util;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
|
|
||||||
/** 提取供应商业务响应,兼容 BAB7 包装报文。 */
|
|
||||||
public class MallBridgeResponseUtil {
|
|
||||||
public static JSONObject parse(String response) {
|
|
||||||
if (StrUtil.isBlank(response)) {
|
|
||||||
throw new IllegalArgumentException("供应商接口返回为空");
|
|
||||||
}
|
|
||||||
JSONObject payload = JSONUtil.parseObj(response);
|
|
||||||
if (!payload.containsKey("resultCode")) {
|
|
||||||
JSONObject data = payload.getJSONObject("data");
|
|
||||||
JSONObject body = data == null ? null : data.getJSONObject("Body");
|
|
||||||
JSONObject header = body == null ? null : body.getJSONObject("RspSvcHeader");
|
|
||||||
if (header == null || !"000000000000".equals(header.getStr("ReturnCode"))) {
|
|
||||||
throw new IllegalArgumentException(header == null ? "BAB7返回报文格式异常" :
|
|
||||||
StrUtil.blankToDefault(header.getStr("ReturnMsg"), "BAB7调用失败"));
|
|
||||||
}
|
|
||||||
JSONObject serviceBody = body.getJSONObject("RspSvcBody");
|
|
||||||
if (serviceBody == null || !"200".equals(serviceBody.getStr("ReturnStCd"))) {
|
|
||||||
throw new IllegalArgumentException("BAB7调用供应商接口失败");
|
|
||||||
}
|
|
||||||
String content = serviceBody.getStr("ReturnCntnt");
|
|
||||||
if (StrUtil.isBlank(content)) {
|
|
||||||
throw new IllegalArgumentException("供应商业务响应为空");
|
|
||||||
}
|
|
||||||
payload = JSONUtil.parseObj(content);
|
|
||||||
}
|
|
||||||
if (payload.getInt("resultCode") == null) {
|
|
||||||
throw new IllegalArgumentException("供应商业务响应缺少结果码");
|
|
||||||
}
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-66
@@ -2,98 +2,33 @@ package com.budwk.app.zhgh.pointsmall.order.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.io.FileTypeUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.enums.SysFileEngineTypeEnum;
|
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInvoiceInfoQueryService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
import com.budwk.app.zhgh.pointsmall.order.enums.MallOrderStatusEnum;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSubHistory;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSubHistory;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.result.SubOrderBuildResult;
|
import com.budwk.app.zhgh.pointsmall.order.result.SubOrderBuildResult;
|
||||||
import com.budwk.app.zhgh.pointsmall.order.service.PointsMallOrderSubHistoryService;
|
import com.budwk.app.zhgh.pointsmall.order.service.PointsMallOrderSubHistoryService;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class PointsMallOrderSubHistoryServiceImpl extends BaseServiceImpl<PointsMallOrderSubHistory> implements PointsMallOrderSubHistoryService {
|
public class PointsMallOrderSubHistoryServiceImpl extends BaseServiceImpl<PointsMallOrderSubHistory> implements PointsMallOrderSubHistoryService {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MallInvoiceInfoQueryService mallInvoiceInfoQueryService;
|
|
||||||
@Inject
|
|
||||||
private SysFileService sysFileService;
|
|
||||||
|
|
||||||
public PointsMallOrderSubHistoryServiceImpl(Dao dao) {
|
public PointsMallOrderSubHistoryServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OrderProInfoDTO> getPictureBase64(String supplierId, String orderId, String queryType, List<OrderProInfoDTO> orderProInfo) {
|
public List<OrderProInfoDTO> getPictureBase64(String supplierId, String orderId, String queryType, List<OrderProInfoDTO> orderProInfo) {
|
||||||
if (CollUtil.isEmpty(orderProInfo)) {
|
return CollUtil.isEmpty(orderProInfo) ? Collections.emptyList() : orderProInfo;
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
List<String> fileIds = orderProInfo.stream().map(OrderProInfoDTO::getSku)
|
|
||||||
.filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
|
|
||||||
if (fileIds.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("商品SKU为空,无法获取商品图片");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 供应商按子订单和 SKU 返回图片 Base64,订单只保存工会文件服务地址。
|
|
||||||
MallPictureOutboundResult result = mallInvoiceInfoQueryService.queryFiles(supplierId, orderId, queryType, fileIds);
|
|
||||||
Map<String, String> localUrls = new LinkedHashMap<>();
|
|
||||||
for (OrderProInfoDTO product : orderProInfo) {
|
|
||||||
String sku = product.getSku();
|
|
||||||
if (StrUtil.isBlank(sku)) {
|
|
||||||
throw new IllegalArgumentException("商品SKU为空,无法获取商品图片");
|
|
||||||
}
|
|
||||||
String localUrl = localUrls.get(sku);
|
|
||||||
if (localUrl == null) {
|
|
||||||
String base64 = result.getImageEncodeMap() == null ? null : result.getImageEncodeMap().get(sku);
|
|
||||||
if (StrUtil.isBlank(base64)) {
|
|
||||||
if (CollUtil.isEmpty(product.getPicInfo()) && StrUtil.isBlank(product.getFilePath()) && StrUtil.isBlank(product.getFileId())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("未获取到商品图片Base64:" + sku);
|
|
||||||
}
|
|
||||||
if (base64.startsWith("data:")) {
|
|
||||||
base64 = base64.substring(base64.indexOf(',') + 1);
|
|
||||||
}
|
|
||||||
byte[] bytes = Base64.getDecoder().decode(base64.replaceAll("\\s", ""));
|
|
||||||
String fileType = FileTypeUtil.getType(new ByteArrayInputStream(bytes));
|
|
||||||
if (bytes.length == 0 || fileType == null || !fileType.matches("(?i)jpg|jpeg|png|gif|bmp|webp")) {
|
|
||||||
throw new IllegalArgumentException("商品图片内容为空或格式不支持:" + sku);
|
|
||||||
}
|
|
||||||
localUrl = sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(),
|
|
||||||
"product-" + UUID.randomUUID() + "." + fileType.toLowerCase(java.util.Locale.ROOT), bytes);
|
|
||||||
if (StrUtil.isBlank(localUrl)) {
|
|
||||||
throw new IllegalArgumentException("商品图片上传失败:" + sku);
|
|
||||||
}
|
|
||||||
localUrls.put(sku, localUrl);
|
|
||||||
}
|
|
||||||
product.setPicInfo(Collections.singletonList(localUrl));
|
|
||||||
product.setFilePath(localUrl);
|
|
||||||
product.setFileId(localUrl);
|
|
||||||
}
|
|
||||||
return orderProInfo;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("商品图片同步失败:" + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+6
-2
@@ -48,11 +48,15 @@ public class PointsMallReconciliationController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@At("/execute")
|
@At
|
||||||
@SLog(tag = "积分商城对账管理", msg = "执行订单对账")
|
@SLog(tag = "积分商城对账管理", msg = "执行订单对账")
|
||||||
@SaCheckPermission("points.mall.reconciliation")
|
@SaCheckPermission("points.mall.reconciliation")
|
||||||
public Result execute(PointsMallReconciliationParam param) {
|
public Result execute(PointsMallReconciliationParam param) {
|
||||||
return pointsMallReconciliationService.executeReconciliation(param);
|
try {
|
||||||
|
return Result.success(pointsMallReconciliationService.execute(param));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
|||||||
-4
@@ -8,10 +8,6 @@ public class PointsMallReconciliationParam {
|
|||||||
private String supplierId;
|
private String supplierId;
|
||||||
private Integer reconciliationType;
|
private Integer reconciliationType;
|
||||||
private String orderId;
|
private String orderId;
|
||||||
private String queryOrderId;
|
|
||||||
private String userId;
|
|
||||||
private Integer reconciliationStatus;
|
|
||||||
private Integer invoiceStatus;
|
|
||||||
private String startDate;
|
private String startDate;
|
||||||
private String endDate;
|
private String endDate;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.reconciliation.service;
|
package com.budwk.app.zhgh.pointsmall.reconciliation.service;
|
||||||
|
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.result.Result;
|
|
||||||
import com.budwk.app.base.service.BaseService;
|
import com.budwk.app.base.service.BaseService;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationOrderPageParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationOrderPageParam;
|
||||||
@@ -19,7 +18,7 @@ public interface PointsMallReconciliationService extends BaseService<PointsMallR
|
|||||||
|
|
||||||
BigDecimal pointsTotal(PointsMallReconciliationParam param);
|
BigDecimal pointsTotal(PointsMallReconciliationParam param);
|
||||||
|
|
||||||
Result executeReconciliation(PointsMallReconciliationParam param);
|
String execute(PointsMallReconciliationParam param);
|
||||||
|
|
||||||
Pagination<Record> recordPage(PointsMallReconciliationRecordPageParam param);
|
Pagination<Record> recordPage(PointsMallReconciliationRecordPageParam param);
|
||||||
|
|
||||||
|
|||||||
+85
-406
@@ -2,66 +2,35 @@ package com.budwk.app.zhgh.pointsmall.reconciliation.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.result.Result;
|
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoByReconciliationDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryReconciliationInfoDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.ReconciliationResultNoticeDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.ReconciliationResultOrderDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.UnReconciledMsgNoticeDTO;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallReconciliationInfoQueryService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallReconciliationResultNoticeService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallUnReconciledMsgNoticeService;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
|
||||||
|
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationOrder;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationOrderPageParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationOrderPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationRecordPageParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.param.PointsMallReconciliationRecordPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliation.service.PointsMallReconciliationService;
|
import com.budwk.app.zhgh.pointsmall.reconciliation.service.PointsMallReconciliationService;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.dao.Chain;
|
import org.nutz.dao.Chain;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.entity.Record;
|
import org.nutz.dao.entity.Record;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对账功能
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsMallReconciliationRecord> implements PointsMallReconciliationService {
|
public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsMallReconciliationRecord> implements PointsMallReconciliationService {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MallReconciliationInfoQueryService mallReconciliationInfoQueryService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MallUnReconciledMsgNoticeService unReconciledMsgNoticeService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MallReconciliationResultNoticeService reconciliationResultNoticeService;
|
|
||||||
|
|
||||||
public PointsMallReconciliationServiceImpl(Dao dao) {
|
public PointsMallReconciliationServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
@@ -84,148 +53,37 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
|
|||||||
return record == null || record.get("totalPoints") == null ? BigDecimal.ZERO : new BigDecimal(record.get("totalPoints").toString());
|
return record == null || record.get("totalPoints") == null ? BigDecimal.ZERO : new BigDecimal(record.get("totalPoints").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行对账
|
|
||||||
*
|
|
||||||
* @param reconciliationBO 入参
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Result executeReconciliation(PointsMallReconciliationParam reconciliationBO) {
|
public String execute(PointsMallReconciliationParam param) {
|
||||||
try {
|
checkReconciliationParam(param);
|
||||||
checkReconciliationParam(reconciliationBO);
|
List<PointsMallOrderSub> orders = dao().query(PointsMallOrderSub.class, reconciliationCnd(param, ""));
|
||||||
} catch (IllegalArgumentException e) {
|
if (CollUtil.isEmpty(orders)) {
|
||||||
return Result.error(e.getMessage());
|
return "未查询到待对账订单";
|
||||||
}
|
|
||||||
Integer reconciliationType = reconciliationBO.getReconciliationType();
|
|
||||||
|
|
||||||
// 从积分商城订单表查询对账订单
|
|
||||||
List<PointsMallOrderSub> orderInfoList = dao().query(PointsMallOrderSub.class, reconciliationCnd(reconciliationBO, ""));
|
|
||||||
if (CollUtil.isEmpty(orderInfoList)) {
|
|
||||||
return Result.error("积分商城没有查询到对账订单数据");
|
|
||||||
}
|
|
||||||
Set<String> orderIdList = orderInfoList.stream().map(PointsMallOrderSub::getOrderId).collect(Collectors.toSet());
|
|
||||||
if (StrUtil.isNotBlank(reconciliationBO.getOrderId())
|
|
||||||
&& !orderIdList.containsAll(StrUtil.splitTrim(reconciliationBO.getOrderId(), ","))) {
|
|
||||||
return Result.error("部分勾选订单已不符合对账条件,请重新查询后选择");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryReconciliationInfoDTO queryReconciliationInfoDTO = new QueryReconciliationInfoDTO();
|
String batchNo = DateUtil.format(new Date(), "yyyyMMddHHmmss") + IdUtil.fastSimpleUUID().substring(0, 6);
|
||||||
queryReconciliationInfoDTO.setSupplierId(reconciliationBO.getSupplierId());
|
int success = 0;
|
||||||
queryReconciliationInfoDTO.setReconciliationType(reconciliationType);
|
int exception = 0;
|
||||||
queryReconciliationInfoDTO.setOrderId(String.join(",", orderIdList));
|
List<PointsMallReconciliationRecord> records = new ArrayList<>();
|
||||||
queryReconciliationInfoDTO.setStartDate(reconciliationBO.getStartDate());
|
|
||||||
queryReconciliationInfoDTO.setEndDate(reconciliationBO.getEndDate());
|
for (PointsMallOrderSub order : orders) {
|
||||||
queryReconciliationInfoDTO.setPage(1);
|
PointsMallReconciliationOrder supplierOrder = dao().fetch(PointsMallReconciliationOrder.class,
|
||||||
queryReconciliationInfoDTO.setPageSize(100);
|
Cnd.where("orderId", "=", order.getOrderId())
|
||||||
// 通过对账接口从供应商拉取对账订单数据
|
.and("supplierId", "=", order.getSupplierId())
|
||||||
List<OrderInfoByReconciliationDTO> result = mallReconciliationInfoQueryService.queryReconciliationInfo(queryReconciliationInfoDTO);
|
.and("delFlag", "=", false));
|
||||||
if (CollUtil.isEmpty(result)) {
|
PointsMallReconciliationRecord record = buildRecord(order, supplierOrder, batchNo);
|
||||||
return Result.error("供应商侧没有拉取到对账订单数据");
|
if (record.getDiffType() == null || record.getDiffType() == 0) {
|
||||||
|
success++;
|
||||||
|
dao().update(PointsMallOrderSub.class, Chain.make("reconciliationStatus", 1), Cnd.where("id", "=", order.getId()));
|
||||||
|
} else {
|
||||||
|
exception++;
|
||||||
|
dao().update(PointsMallOrderSub.class, Chain.make("reconciliationStatus", 2), Cnd.where("id", "=", order.getId()));
|
||||||
}
|
}
|
||||||
result = result.stream().filter(o -> orderIdList.contains(o.getOrderId())).collect(Collectors.toList());
|
records.add(record);
|
||||||
String supplierId = reconciliationBO.getSupplierId();
|
|
||||||
result.forEach(o -> o.setSupplierId(supplierId));
|
|
||||||
// 根据供应商ID + 订单ID进行分组
|
|
||||||
Map<String, List<OrderInfoByReconciliationDTO>> supplierOrderList = result.stream()
|
|
||||||
.collect(Collectors.groupingBy(o -> String.join("-", o.getSupplierId(), o.getOrderId())));
|
|
||||||
|
|
||||||
// 根据供应商ID + 订单ID进行分组
|
|
||||||
Map<String, List<PointsMallOrderSub>> pfOrderList = orderInfoList.stream()
|
|
||||||
.collect(Collectors.groupingBy(o -> String.join("-", o.getSupplierId(), o.getOrderId())));
|
|
||||||
|
|
||||||
Set<String> pfKeySet = pfOrderList.keySet();
|
|
||||||
Set<String> supplierKeySet = supplierOrderList.keySet();
|
|
||||||
// 浦发商城和供应商都存在的订单
|
|
||||||
Set<String> sameKeySet = pfKeySet.stream().filter(supplierKeySet::contains).collect(Collectors.toSet());
|
|
||||||
// 1.浦发商城和供应商两边的《供应商ID + 订单ID》可以匹配上
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList1 = getReconciliationResult(sameKeySet, pfOrderList, supplierOrderList);
|
|
||||||
if (CollUtil.isNotEmpty(reconciliationList1)) {
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList0 = reconciliationList1.stream()
|
|
||||||
.filter(o -> o.getDiffType() == 3).collect(Collectors.toList());
|
|
||||||
if (CollUtil.isNotEmpty(reconciliationList0)) {
|
|
||||||
UnReconciledMsgNoticeDTO noticeDTO = getUnReconciledMsgNoticeDTO(reconciliationBO, reconciliationList0);
|
|
||||||
noticeDTO.setOrderIds(reconciliationList0.stream().map(PointsMallReconciliationRecord::getOrderId).collect(Collectors.joining(",")));
|
|
||||||
// 更新子订单状态为对账异常
|
|
||||||
subOrderReconciliationUpdate(reconciliationList0, 2);
|
|
||||||
// 对账异常结果通知接口
|
|
||||||
unReconciledMsgNoticeService.unReconciledMsgNotice(noticeDTO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationSuccessList = reconciliationList1.stream()
|
dao().insert(records);
|
||||||
.filter(o -> o.getDiffType() == 0).collect(Collectors.toList());
|
return "对账完成,批次号:" + batchNo + ",成功:" + success + ",异常:" + exception;
|
||||||
if (CollUtil.isNotEmpty(reconciliationSuccessList)) {
|
|
||||||
// 更新子订单状态为对账完成
|
|
||||||
subOrderReconciliationUpdate(reconciliationSuccessList, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.积分商城已确认收货,对账接口未返回
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList2 = orderNotReturn(pfKeySet, supplierKeySet, pfOrderList);
|
|
||||||
if (CollUtil.isNotEmpty(reconciliationList2)) {
|
|
||||||
reconciliationList1.addAll(reconciliationList2);
|
|
||||||
UnReconciledMsgNoticeDTO noticeDTO = getUnReconciledMsgNoticeDTO(reconciliationBO, reconciliationList2);
|
|
||||||
noticeDTO.setOrderIds(reconciliationList2.stream().map(PointsMallReconciliationRecord::getOrderId).collect(Collectors.joining(",")));
|
|
||||||
// 更新子订单状态为对账异常
|
|
||||||
subOrderReconciliationUpdate(reconciliationList2, 2);
|
|
||||||
// 对账异常结果通知接口
|
|
||||||
unReconciledMsgNoticeService.unReconciledMsgNotice(noticeDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3.积分商城不存在此订单,无法对账
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList3 = orderNotExist(supplierKeySet, pfKeySet, supplierOrderList);
|
|
||||||
if (CollUtil.isNotEmpty(reconciliationList3)) {
|
|
||||||
reconciliationList1.addAll(reconciliationList3);
|
|
||||||
UnReconciledMsgNoticeDTO noticeDTO = getUnReconciledMsgNoticeDTO(reconciliationBO, reconciliationList3);
|
|
||||||
noticeDTO.setOrderIds(reconciliationList3.stream().map(PointsMallReconciliationRecord::getOrderId).collect(Collectors.joining(",")));
|
|
||||||
// 更新子订单状态为对账异常
|
|
||||||
// subOrderReconciliationUpdate(reconciliationList3, 2);
|
|
||||||
// 对账异常结果通知接口
|
|
||||||
unReconciledMsgNoticeService.unReconciledMsgNotice(noticeDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CollUtil.isNotEmpty(reconciliationList1)) {
|
|
||||||
String startDate = reconciliationBO.getStartDate();
|
|
||||||
String endDate = reconciliationBO.getEndDate();
|
|
||||||
String startEndDate = StrUtil.blankToDefault(startDate, "history").replace("-", "")
|
|
||||||
+ StrUtil.blankToDefault(endDate, "").replace("-", "");
|
|
||||||
String loginName = StrUtil.blankToDefault(SecurityUtil.getUserId(), "console");
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
String yyyyMMddHHmm = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
|
|
||||||
reconciliationList1.forEach(o ->
|
|
||||||
o.setBatchNo(String.format("%s-%s-%s", startEndDate, loginName, yyyyMMddHHmm)));
|
|
||||||
// 把对账结果写入数据库
|
|
||||||
dao().insert(reconciliationList1);
|
|
||||||
|
|
||||||
ReconciliationResultNoticeDTO resultNoticeDTO = new ReconciliationResultNoticeDTO();
|
|
||||||
resultNoticeDTO.setSupplierId(reconciliationBO.getSupplierId());
|
|
||||||
resultNoticeDTO.setReconciliationBatchNo(reconciliationList1.get(0).getBatchNo());
|
|
||||||
resultNoticeDTO.setReconciliationTime(now.toString());
|
|
||||||
resultNoticeDTO.setReconciliationResults(reconciliationList1.stream().map(o -> {
|
|
||||||
ReconciliationResultOrderDTO resultOrderDTO = new ReconciliationResultOrderDTO();
|
|
||||||
resultOrderDTO.setOrderId(o.getOrderId());
|
|
||||||
if (StrUtil.isNotBlank(o.getUserId())) {
|
|
||||||
Sys_user user = dao().fetch(Sys_user.class, o.getUserId());
|
|
||||||
if (user == null || StrUtil.isBlank(user.getVirtualId())) {
|
|
||||||
throw new IllegalArgumentException("用户虚拟ID未配置或不存在");
|
|
||||||
}
|
|
||||||
resultOrderDTO.setUserId(user.getVirtualId());
|
|
||||||
}
|
|
||||||
resultOrderDTO.setReconciliationStatus(o.getDiffType() == 0 ? 1 : 2);
|
|
||||||
resultOrderDTO.setDiffType(o.getDiffType());
|
|
||||||
resultOrderDTO.setDiffReason(o.getDiffReason());
|
|
||||||
resultOrderDTO.setPlatformTotalPrice(o.getPTotalPrice());
|
|
||||||
resultOrderDTO.setPlatformCashAmount(o.getPCashAmount());
|
|
||||||
resultOrderDTO.setPlatformPointsPrice(o.getPPointsPrice());
|
|
||||||
resultOrderDTO.setPlatformRefundPrice(o.getPRefund());
|
|
||||||
resultOrderDTO.setSupplierTotalPrice(o.getSTotalPrice());
|
|
||||||
resultOrderDTO.setSupplierCashAmount(o.getSCashAmount());
|
|
||||||
resultOrderDTO.setSupplierPointsPrice(o.getSPointsPrice());
|
|
||||||
resultOrderDTO.setSupplierRefundPrice(o.getSRefund());
|
|
||||||
return resultOrderDTO;
|
|
||||||
}).collect(Collectors.toList()));
|
|
||||||
reconciliationResultNoticeService.reconciliationResultNotice(resultNoticeDTO);
|
|
||||||
}
|
|
||||||
return Result.success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -235,21 +93,21 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
|
|||||||
cnd.and("r.supplierId", "=", param.getSupplierId());
|
cnd.and("r.supplierId", "=", param.getSupplierId());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getOrderId())) {
|
if (StrUtil.isNotBlank(param.getOrderId())) {
|
||||||
cnd.and("r.orderId", "=", param.getOrderId());
|
cnd.and("r.orderId", "like", "%" + param.getOrderId() + "%");
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getUserId())) {
|
if (StrUtil.isNotBlank(param.getUserId())) {
|
||||||
cnd.and("r.userId", "=", param.getUserId());
|
cnd.and("r.userId", "like", "%" + param.getUserId() + "%");
|
||||||
}
|
}
|
||||||
if (param.getDiffType() != null) {
|
if (param.getDiffType() != null) {
|
||||||
cnd.and("r.diffType", "=", param.getDiffType());
|
cnd.and("r.diffType", "=", param.getDiffType());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getBatchNo())) {
|
if (StrUtil.isNotBlank(param.getBatchNo())) {
|
||||||
cnd.and("r.batchNo", "=", param.getBatchNo());
|
cnd.and("r.batchNo", "like", "%" + param.getBatchNo() + "%");
|
||||||
}
|
}
|
||||||
if (param.getNoticeStatus() != null) {
|
if (param.getNoticeStatus() != null) {
|
||||||
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
|
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
|
||||||
}
|
}
|
||||||
cnd.desc("r.batchNo").desc("r.createdAt");
|
cnd.desc("r.createdAt");
|
||||||
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
|
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
return listPageMap(param.getPageNumber(), param.getPageSize(), sql);
|
return listPageMap(param.getPageNumber(), param.getPageSize(), sql);
|
||||||
@@ -261,8 +119,7 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Cnd orderCnd(PointsMallReconciliationOrderPageParam param, String alias) {
|
private Cnd orderCnd(PointsMallReconciliationOrderPageParam param, String alias) {
|
||||||
Cnd cnd = Cnd.where(field(alias, "delFlag"), "=", false)
|
Cnd cnd = Cnd.where(field(alias, "delFlag"), "=", false);
|
||||||
.and(field(alias, "orderState"), "=", 5);
|
|
||||||
if (StrUtil.isNotBlank(param.getSupplierId())) {
|
if (StrUtil.isNotBlank(param.getSupplierId())) {
|
||||||
cnd.and(field(alias, "supplierId"), "=", param.getSupplierId());
|
cnd.and(field(alias, "supplierId"), "=", param.getSupplierId());
|
||||||
}
|
}
|
||||||
@@ -288,23 +145,22 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Cnd reconciliationCnd(PointsMallReconciliationParam param, String alias) {
|
private Cnd reconciliationCnd(PointsMallReconciliationParam param, String alias) {
|
||||||
PointsMallReconciliationOrderPageParam query = new PointsMallReconciliationOrderPageParam();
|
Cnd cnd = Cnd.where(field(alias, "delFlag"), "=", false);
|
||||||
query.setSupplierId(param.getSupplierId());
|
cnd.and(field(alias, "supplierId"), "=", param.getSupplierId());
|
||||||
query.setOrderId(param.getQueryOrderId());
|
|
||||||
query.setUserId(param.getUserId());
|
|
||||||
query.setReconciliationStatus(param.getReconciliationStatus());
|
|
||||||
query.setInvoiceStatus(param.getInvoiceStatus());
|
|
||||||
query.setStartDate(param.getStartDate());
|
|
||||||
query.setEndDate(param.getEndDate());
|
|
||||||
Cnd cnd = orderCnd(query, alias);
|
|
||||||
if (param.getReconciliationType() != null && param.getReconciliationType() == 2) {
|
if (param.getReconciliationType() != null && param.getReconciliationType() == 2) {
|
||||||
cnd.and(field(alias, "reconciliationStatus"), "=", 2);
|
cnd.and(field(alias, "reconciliationStatus"), "=", 2);
|
||||||
} else {
|
} else {
|
||||||
cnd.and(field(alias, "reconciliationStatus"), "=", 0);
|
cnd.and(field(alias, "reconciliationStatus"), "=", 0);
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getOrderId())) {
|
if (StrUtil.isNotBlank(param.getOrderId())) {
|
||||||
cnd.and(field(alias, "orderId"), "in", StrUtil.splitTrim(param.getOrderId(), ","));
|
List<String> orderIds = StrUtil.splitTrim(param.getOrderId(), ",");
|
||||||
|
if (orderIds.size() > 1) {
|
||||||
|
cnd.and(field(alias, "orderId"), "in", orderIds);
|
||||||
|
} else {
|
||||||
|
cnd.and(field(alias, "orderId"), "like", "%" + param.getOrderId() + "%");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
addDateRange(cnd, alias, param.getStartDate(), param.getEndDate());
|
||||||
return cnd;
|
return cnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,233 +190,56 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
|
|||||||
if (StrUtil.isBlank(param.getStartDate()) || StrUtil.isBlank(param.getEndDate())) {
|
if (StrUtil.isBlank(param.getStartDate()) || StrUtil.isBlank(param.getEndDate())) {
|
||||||
throw new IllegalArgumentException("对账日期不能为空");
|
throw new IllegalArgumentException("对账日期不能为空");
|
||||||
}
|
}
|
||||||
if (param.getReconciliationType() != 1 && param.getReconciliationType() != 2) {
|
|
||||||
throw new IllegalArgumentException("对账类型不正确");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void subOrderReconciliationUpdate(List<PointsMallReconciliationRecord> reconciliationList, Integer reconciliationStatus) {
|
private PointsMallReconciliationRecord buildRecord(PointsMallOrderSub order, PointsMallReconciliationOrder supplierOrder, String batchNo) {
|
||||||
// 更新子订单状态为对账异常
|
PointsMallReconciliationRecord record = new PointsMallReconciliationRecord();
|
||||||
reconciliationList.forEach(o -> dao().update(PointsMallOrderSub.class,
|
record.setSupplierId(order.getSupplierId());
|
||||||
Chain.make("reconciliationStatus", reconciliationStatus),
|
record.setOrderId(order.getOrderId());
|
||||||
Cnd.where("orderId", "=", o.getOrderId()).and("supplierId", "=", o.getSupplierId())));
|
record.setUserId(order.getUserId());
|
||||||
|
record.setPRefund(nullToZero(order.getRefund()));
|
||||||
|
record.setPTotalPrice(nullToZero(order.getTotalPrice()));
|
||||||
|
record.setPCashAmount(nullToZero(order.getWPayOrAPay()));
|
||||||
|
record.setPPointsPrice(nullToZero(order.getPointsPrice()));
|
||||||
|
record.setBatchNo(batchNo);
|
||||||
|
record.setNoticeStatus(0);
|
||||||
|
record.setPushTime(0);
|
||||||
|
|
||||||
|
if (supplierOrder == null) {
|
||||||
|
record.setSRefund(BigDecimal.ZERO);
|
||||||
|
record.setSTotalPrice(record.getPTotalPrice());
|
||||||
|
record.setSCashAmount(record.getPCashAmount());
|
||||||
|
record.setSPointsPrice(record.getPPointsPrice());
|
||||||
|
record.setDiffType(0);
|
||||||
|
record.setDiffReason("未获取到供应商侧对账订单,按平台订单确认");
|
||||||
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnReconciledMsgNoticeDTO getUnReconciledMsgNoticeDTO(PointsMallReconciliationParam reconciliationBO,
|
record.setSRefund(BigDecimal.ZERO);
|
||||||
List<PointsMallReconciliationRecord> reconciliationList2) {
|
record.setSTotalPrice(nullToZero(supplierOrder.getTotalPrice()));
|
||||||
UnReconciledMsgNoticeDTO noticeDTO = new UnReconciledMsgNoticeDTO();
|
record.setSCashAmount(BigDecimal.ZERO);
|
||||||
noticeDTO.setUniqueSeqNo("111");
|
record.setSPointsPrice(nullToZero(supplierOrder.getTotalPrice()));
|
||||||
noticeDTO.setToken("token");
|
|
||||||
noticeDTO.setSupplierId(reconciliationBO.getSupplierId());
|
List<String> reasons = new ArrayList<>();
|
||||||
noticeDTO.setStartDate(reconciliationBO.getStartDate());
|
if (!amountEquals(record.getPTotalPrice(), record.getSTotalPrice())) {
|
||||||
noticeDTO.setEndDate(reconciliationBO.getEndDate());
|
reasons.add("订单总金额不一致");
|
||||||
PointsMallReconciliationRecord reconciliation = reconciliationList2.get(0);
|
}
|
||||||
noticeDTO.setUnReconciledType(reconciliation.getDiffType() + "");
|
if (!amountEquals(record.getPPointsPrice(), record.getSPointsPrice())) {
|
||||||
noticeDTO.setUnReconciledMsg(reconciliation.getDiffReason());
|
reasons.add("积分金额不一致");
|
||||||
return noticeDTO;
|
}
|
||||||
|
if (!Objects.equals(order.getUserId(), supplierOrder.getUserId())) {
|
||||||
|
reasons.add("用户ID不一致");
|
||||||
|
}
|
||||||
|
record.setDiffType(reasons.isEmpty() ? 0 : 1);
|
||||||
|
record.setDiffReason(reasons.isEmpty() ? "对账一致" : String.join(";", reasons));
|
||||||
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private BigDecimal nullToZero(BigDecimal value) {
|
||||||
* 积分商城已确认收货,对账接口未返回
|
return value == null ? BigDecimal.ZERO : value;
|
||||||
*
|
|
||||||
* @param pfKeySet 浦发key
|
|
||||||
* @param supplierKeySet 供应商key
|
|
||||||
* @param pfOrderList 浦发商城对账订单
|
|
||||||
* @return 异常订单
|
|
||||||
*/
|
|
||||||
private List<PointsMallReconciliationRecord> orderNotReturn(Set<String> pfKeySet, Set<String> supplierKeySet,
|
|
||||||
Map<String, List<PointsMallOrderSub>> pfOrderList) {
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList = new ArrayList<>();
|
|
||||||
pfKeySet.stream().filter(key -> !supplierKeySet.contains(key)).forEach(key -> {
|
|
||||||
List<PointsMallOrderSub> pfOrders = pfOrderList.get(key);
|
|
||||||
if (CollUtil.isNotEmpty(pfOrders)) {
|
|
||||||
reconciliationList.add(buildReconciliationRecord(null, pfOrders.get(0), 1, "积分商城已确认收货,对账接口未返回"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return reconciliationList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private boolean amountEquals(BigDecimal left, BigDecimal right) {
|
||||||
* 积分商城不存在此订单,无法对账
|
return nullToZero(left).compareTo(nullToZero(right)) == 0;
|
||||||
*
|
|
||||||
* @param supplierKeySet 供应商key
|
|
||||||
* @param pfKeySet 浦发key
|
|
||||||
* @param supplierOrderList 供应商对账订单
|
|
||||||
* @return 异常订单
|
|
||||||
*/
|
|
||||||
private List<PointsMallReconciliationRecord> orderNotExist(Set<String> supplierKeySet, Set<String> pfKeySet,
|
|
||||||
Map<String, List<OrderInfoByReconciliationDTO>> supplierOrderList) {
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList = new ArrayList<>();
|
|
||||||
supplierKeySet.stream().filter(key -> !pfKeySet.contains(key)).forEach(key -> {
|
|
||||||
List<OrderInfoByReconciliationDTO> supplierOrders = supplierOrderList.get(key);
|
|
||||||
if (CollUtil.isNotEmpty(supplierOrders)) {
|
|
||||||
reconciliationList.add(buildReconciliationRecord(supplierOrders.get(0), null, 2, "积分商城不存在此订单,无法对账"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return reconciliationList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 浦发商城和供应商两边的《供应商ID + 订单ID》可以匹配上
|
|
||||||
*
|
|
||||||
* @param sameKeySet 双方都存在的订单ID
|
|
||||||
* @param pfOrderList 浦发商城的订单
|
|
||||||
* @param supplierOrderList 供应商的订单
|
|
||||||
* @return 对账结果
|
|
||||||
*/
|
|
||||||
private List<PointsMallReconciliationRecord> getReconciliationResult(Set<String> sameKeySet,
|
|
||||||
Map<String, List<PointsMallOrderSub>> pfOrderList,
|
|
||||||
Map<String, List<OrderInfoByReconciliationDTO>> supplierOrderList) {
|
|
||||||
List<PointsMallReconciliationRecord> reconciliationList = new ArrayList<>();
|
|
||||||
sameKeySet.forEach(key -> {
|
|
||||||
List<PointsMallOrderSub> pOrderList = pfOrderList.get(key);
|
|
||||||
List<OrderInfoByReconciliationDTO> sOrderList = supplierOrderList.get(key);
|
|
||||||
BigDecimal pfPointSum = pOrderList.stream()
|
|
||||||
.map(o -> (o.getPointsPrice() == null ? BigDecimal.ZERO : o.getPointsPrice())
|
|
||||||
.subtract(o.getRefund() == null ? BigDecimal.ZERO : o.getRefund()))
|
|
||||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
||||||
BigDecimal supplierPointSum = sOrderList.stream()
|
|
||||||
.map(OrderInfoByReconciliationDTO::getTotalPrice)
|
|
||||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
||||||
// 根据供应商ID和订单ID比对积分总金额是否一致
|
|
||||||
if (pfPointSum.compareTo(supplierPointSum) != 0) {
|
|
||||||
reconciliationList.add(buildReconciliationRecord(sOrderList.get(0), pOrderList.get(0), 3, "订单内容不一致,订单金额不一致"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CollUtil.isNotEmpty(pOrderList)) {
|
|
||||||
OrderInfoByReconciliationDTO sOrder = sOrderList.get(0);
|
|
||||||
PointsMallOrderSub pfOrder = pOrderList.get(0);
|
|
||||||
PointsMallReconciliationRecord reconciliation = buildReconciliationRecord(sOrder, pfOrder, 0, "无差异");
|
|
||||||
// 比对商品明细的sku,商品数量,商品价格,商品税率是否一致
|
|
||||||
if (CollUtil.isNotEmpty(sOrderList)) {
|
|
||||||
String productInfo = pfOrder.getExtJson();
|
|
||||||
// 解析积分商品下的商品明细
|
|
||||||
List<OrderProInfoDTO> pfOrderProList = JSONUtil.toList(productInfo, OrderProInfoDTO.class);
|
|
||||||
// 处理商品名称、价格、税率的小数位(不参与比较的字段)
|
|
||||||
handleField(pfOrderProList);
|
|
||||||
|
|
||||||
// 从对账接口获取的订单商品
|
|
||||||
OrderInfoByReconciliationDTO supplierOrder = sOrderList.get(0);
|
|
||||||
List<OrderProInfoDTO> supplierOrderProList = supplierOrder.getOrderProInfos();
|
|
||||||
handleField(supplierOrderProList);
|
|
||||||
|
|
||||||
// 比较双方商品明细是否一致
|
|
||||||
if (!compareProduct(pfOrderProList, supplierOrderProList)) {
|
|
||||||
reconciliation.setDiffType(3);
|
|
||||||
reconciliation.setDiffReason("订单内容不一致,商品明细不一致");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reconciliationList.add(reconciliation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return reconciliationList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理商品价格和税率字段的小数位,保证对比的时候小数位一致
|
|
||||||
*
|
|
||||||
* @param productList 订单下的商品集合
|
|
||||||
*/
|
|
||||||
private void handleField(List<OrderProInfoDTO> productList) {
|
|
||||||
// 商品名称不参与比较,价格和税率小数点位数处理
|
|
||||||
productList.forEach(o -> {
|
|
||||||
o.setName(null);
|
|
||||||
if (o.getPrice() != null) {
|
|
||||||
o.setPrice(o.getPrice().setScale(2, RoundingMode.HALF_UP));
|
|
||||||
}
|
|
||||||
if (o.getTaxRate() != null) {
|
|
||||||
o.setTaxRate(o.getTaxRate().setScale(6, RoundingMode.HALF_UP));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较两个list<bean>是否完全一致,不考虑顺序
|
|
||||||
*
|
|
||||||
* @param list1 集合1
|
|
||||||
* @param list2 集合2
|
|
||||||
* @return 是否相同
|
|
||||||
*/
|
|
||||||
private boolean compareProduct(List<OrderProInfoDTO> list1, List<OrderProInfoDTO> list2) {
|
|
||||||
// 1. 如果两个列表是同一个引用,直接返回 true
|
|
||||||
if (list1 == list2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 如果其中有一个为 null,或者商品总数不一致,直接返回 false
|
|
||||||
if (list1 == null || list2 == null || list1.size() != list2.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 遍历第一个订单的商品,检查是否都能在第二个订单中找到匹配的商品
|
|
||||||
for (OrderProInfoDTO p1 : list1) {
|
|
||||||
boolean foundMatch = false;
|
|
||||||
for (OrderProInfoDTO p2 : list2) {
|
|
||||||
// 通过sku+number+price+taxRate相同判定为商品信息一致
|
|
||||||
if (Objects.equals(p1.getSku(), p2.getSku()) &&
|
|
||||||
Objects.equals(p1.getNumber(), p2.getNumber()) &&
|
|
||||||
compareBigDecimal(p1.getPrice(), p2.getPrice()) &&
|
|
||||||
compareBigDecimal(p1.getTaxRate(), p2.getTaxRate())) {
|
|
||||||
foundMatch = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!foundMatch) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean compareBigDecimal(BigDecimal a, BigDecimal b) {
|
|
||||||
// 两者都为空,视为相等
|
|
||||||
if (a == null && b == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// 只有一个为空,视为不相等
|
|
||||||
if (a == null || b == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 都不为空,使用compareTo 比较数值
|
|
||||||
return a.compareTo(b) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单积分对账数据赋值
|
|
||||||
*
|
|
||||||
* @param sOrder 对账接口返回的订单对账数据
|
|
||||||
* @param pOrder 子订单表的订单数据
|
|
||||||
* @param diffType 异常类型
|
|
||||||
* @param diffReason 异常原因
|
|
||||||
* @return 对账结果
|
|
||||||
*/
|
|
||||||
private PointsMallReconciliationRecord buildReconciliationRecord(OrderInfoByReconciliationDTO sOrder,
|
|
||||||
PointsMallOrderSub pOrder,
|
|
||||||
int diffType, String diffReason) {
|
|
||||||
PointsMallReconciliationRecord reconciliation = new PointsMallReconciliationRecord();
|
|
||||||
reconciliation.setDiffType(diffType);
|
|
||||||
reconciliation.setDiffReason(diffReason);
|
|
||||||
reconciliation.setNoticeStatus(0);
|
|
||||||
reconciliation.setPushTime(0);
|
|
||||||
if (sOrder != null) {
|
|
||||||
// 对账接口返回数据
|
|
||||||
reconciliation.setSupplierId(sOrder.getSupplierId());
|
|
||||||
reconciliation.setOrderId(sOrder.getOrderId());
|
|
||||||
reconciliation.setSTotalPrice(sOrder.getTotalPrice());
|
|
||||||
reconciliation.setSPointsPrice(sOrder.getPointsPrice());
|
|
||||||
reconciliation.setSCashAmount(sOrder.getWPayOrAPay());
|
|
||||||
}
|
|
||||||
if (pOrder != null) {
|
|
||||||
// 订单表里数据
|
|
||||||
reconciliation.setSupplierId(pOrder.getSupplierId());
|
|
||||||
reconciliation.setOrderId(pOrder.getOrderId());
|
|
||||||
reconciliation.setUserId(pOrder.getUserId());
|
|
||||||
reconciliation.setPTotalPrice(pOrder.getTotalPrice());
|
|
||||||
reconciliation.setPPointsPrice(pOrder.getPointsPrice());
|
|
||||||
reconciliation.setPCashAmount(pOrder.getWPayOrAPay());
|
|
||||||
reconciliation.setPRefund(pOrder.getRefund());
|
|
||||||
}
|
|
||||||
return reconciliation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -5,13 +5,13 @@ import com.budwk.app.base.service.BaseService;
|
|||||||
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.models.PointsMallReconciliationRecord;
|
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.models.PointsMallReconciliationRecord;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.param.PointsMallReconciliationRecordPageParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.param.PointsMallReconciliationRecordPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
||||||
|
import org.nutz.dao.entity.Record;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface PointsMallReconciliationRecordService extends BaseService<PointsMallReconciliationRecord> {
|
public interface PointsMallReconciliationRecordService extends BaseService<PointsMallReconciliationRecord> {
|
||||||
|
|
||||||
Pagination<Map<String, Object>> page(PointsMallReconciliationRecordPageParam param);
|
Pagination<Record> page(PointsMallReconciliationRecordPageParam param);
|
||||||
|
|
||||||
List<PointsMallSupplier> listSuppliers();
|
List<PointsMallSupplier> listSuppliers();
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-27
@@ -3,7 +3,6 @@ package com.budwk.app.zhgh.pointsmall.reconciliationrecord.service.impl;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.models.PointsMallReconciliationRecord;
|
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.models.PointsMallReconciliationRecord;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.param.PointsMallReconciliationRecordPageParam;
|
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.param.PointsMallReconciliationRecordPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.service.PointsMallReconciliationRecordService;
|
import com.budwk.app.zhgh.pointsmall.reconciliationrecord.service.PointsMallReconciliationRecordService;
|
||||||
@@ -11,14 +10,11 @@ import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
|||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
|
import org.nutz.dao.entity.Record;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class PointsMallReconciliationRecordServiceImpl extends BaseServiceImpl<PointsMallReconciliationRecord> implements PointsMallReconciliationRecordService {
|
public class PointsMallReconciliationRecordServiceImpl extends BaseServiceImpl<PointsMallReconciliationRecord> implements PointsMallReconciliationRecordService {
|
||||||
@@ -28,46 +24,30 @@ public class PointsMallReconciliationRecordServiceImpl extends BaseServiceImpl<P
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pagination<Map<String, Object>> page(PointsMallReconciliationRecordPageParam param) {
|
public Pagination<Record> page(PointsMallReconciliationRecordPageParam param) {
|
||||||
Cnd cnd = Cnd.where("r.delFlag", "=", false);
|
Cnd cnd = Cnd.where("r.delFlag", "=", false);
|
||||||
if (StrUtil.isNotBlank(param.getSupplierId())) {
|
if (StrUtil.isNotBlank(param.getSupplierId())) {
|
||||||
cnd.and("r.supplierId", "=", param.getSupplierId());
|
cnd.and("r.supplierId", "=", param.getSupplierId());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getOrderId())) {
|
if (StrUtil.isNotBlank(param.getOrderId())) {
|
||||||
cnd.and("r.orderId", "=", param.getOrderId());
|
cnd.and("r.orderId", "like", "%" + param.getOrderId() + "%");
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getUserId())) {
|
if (StrUtil.isNotBlank(param.getUserId())) {
|
||||||
List<Sys_user> users = dao().query(Sys_user.class, Cnd.where("loginname", "like", "%" + param.getUserId().trim() + "%")
|
cnd.and("r.userId", "like", "%" + param.getUserId() + "%");
|
||||||
.and("delFlag", "=", false));
|
|
||||||
if (users.isEmpty()) {
|
|
||||||
return new Pagination<>(param.getPageNumber(), param.getPageSize(), 0, Collections.emptyList());
|
|
||||||
}
|
|
||||||
cnd.and("r.userId", "in", users.stream().map(Sys_user::getId).collect(Collectors.toList()));
|
|
||||||
}
|
}
|
||||||
if (param.getDiffType() != null) {
|
if (param.getDiffType() != null) {
|
||||||
cnd.and("r.diffType", "=", param.getDiffType());
|
cnd.and("r.diffType", "=", param.getDiffType());
|
||||||
}
|
}
|
||||||
if (StrUtil.isNotBlank(param.getBatchNo())) {
|
if (StrUtil.isNotBlank(param.getBatchNo())) {
|
||||||
cnd.and("r.batchNo", "=", param.getBatchNo());
|
cnd.and("r.batchNo", "like", "%" + param.getBatchNo() + "%");
|
||||||
}
|
}
|
||||||
if (param.getNoticeStatus() != null) {
|
if (param.getNoticeStatus() != null) {
|
||||||
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
|
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
|
||||||
}
|
}
|
||||||
cnd.desc("r.batchNo").desc("r.createdAt");
|
cnd.desc("r.createdAt");
|
||||||
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
|
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination<Map<String, Object>> page = listPageMap(param.getPageNumber(), param.getPageSize(), sql);
|
return listPageMap(param.getPageNumber(), param.getPageSize(), sql);
|
||||||
if (page.getList() != null && !page.getList().isEmpty()) {
|
|
||||||
List<String> userIds = page.getList().stream().map(record -> (String) record.get("userId"))
|
|
||||||
.filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
|
|
||||||
Map<String, String> loginNames = new HashMap<>();
|
|
||||||
if (!userIds.isEmpty()) {
|
|
||||||
List<Sys_user> users = dao().query(Sys_user.class, Cnd.where("id", "in", userIds).and("delFlag", "=", false));
|
|
||||||
users.forEach(user -> loginNames.put(user.getId(), user.getLoginname()));
|
|
||||||
}
|
|
||||||
page.getList().forEach(record -> record.put("loginname", loginNames.get(record.get("userId"))));
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-39
@@ -1,36 +1,23 @@
|
|||||||
package com.budwk.app.zhgh.pointsmall.supplier.service.impl;
|
package com.budwk.app.zhgh.pointsmall.supplier.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.base.exception.BaseException;
|
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.param.PointsMallSupplierPageParam;
|
import com.budwk.app.zhgh.pointsmall.supplier.param.PointsMallSupplierPageParam;
|
||||||
import com.budwk.app.zhgh.pointsmall.supplier.service.PointsMallSupplierService;
|
import com.budwk.app.zhgh.pointsmall.supplier.service.PointsMallSupplierService;
|
||||||
import org.nutz.dao.Chain;
|
import org.nutz.dao.Chain;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.integration.jedis.RedisService;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class PointsMallSupplierServiceImpl extends BaseServiceImpl<PointsMallSupplier> implements PointsMallSupplierService {
|
public class PointsMallSupplierServiceImpl extends BaseServiceImpl<PointsMallSupplier> implements PointsMallSupplierService {
|
||||||
|
|
||||||
@Inject
|
|
||||||
private RedisService redisService;
|
|
||||||
|
|
||||||
public PointsMallSupplierServiceImpl(Dao dao) {
|
public PointsMallSupplierServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
@@ -65,32 +52,7 @@ public class PointsMallSupplierServiceImpl extends BaseServiceImpl<PointsMallSup
|
|||||||
cnd.and("mallType", "=", mallType);
|
cnd.and("mallType", "=", mallType);
|
||||||
}
|
}
|
||||||
cnd.asc("sortCode");
|
cnd.asc("sortCode");
|
||||||
List<PointsMallSupplier> list = dao().query(PointsMallSupplier.class, cnd);
|
return dao().query(PointsMallSupplier.class, cnd);
|
||||||
if (Objects.equals(1, mallType)) {
|
|
||||||
Sys_user user = dao().fetch(Sys_user.class, SecurityUtil.getUserId());
|
|
||||||
if (user == null || StrUtil.isBlank(user.getVirtualId())) {
|
|
||||||
throw new BaseException("用户不存在");
|
|
||||||
}
|
|
||||||
for (PointsMallSupplier supplier : list) {
|
|
||||||
supplier.setSupplierUrl(getSupplierIndexUrl(user, supplier));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSupplierIndexUrl(Sys_user user, PointsMallSupplier supplier) {
|
|
||||||
String supplierUrl = supplier.getSupplierUrl();
|
|
||||||
if (StrUtil.isBlank(supplierUrl) || !Objects.equals(1, supplier.getMallType())) {
|
|
||||||
return supplierUrl;
|
|
||||||
}
|
|
||||||
Map<String, String> params = new HashMap<>();
|
|
||||||
params.put("userId", user.getVirtualId());
|
|
||||||
if ("10101013".equals(supplier.getSupplierId())) {
|
|
||||||
params.put("orgId", user.getVirtualOrgId());
|
|
||||||
}
|
|
||||||
String keyword = IdUtil.fastSimpleUUID();
|
|
||||||
redisService.setex("supplier-session:" + keyword, 300, JSONUtil.toJsonStr(params));
|
|
||||||
return supplierUrl.concat(keyword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
-1
@@ -127,7 +127,6 @@ public class CondolenceApplyController {
|
|||||||
username as userName,
|
username as userName,
|
||||||
loginname as loginName,
|
loginname as loginName,
|
||||||
sex,
|
sex,
|
||||||
mobile,
|
|
||||||
technicalTitle,
|
technicalTitle,
|
||||||
IFNULL(unitname, '暂无') as unitName,
|
IFNULL(unitname, '暂无') as unitName,
|
||||||
unitid as unitId,
|
unitid as unitId,
|
||||||
@@ -146,6 +145,9 @@ public class CondolenceApplyController {
|
|||||||
}
|
}
|
||||||
if(!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
if(!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||||
if(AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
if(AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
||||||
|
if (StrUtil.isBlank(SecurityUtil.getUnionId())) {
|
||||||
|
return Result.success(java.util.Collections.emptyList());
|
||||||
|
}
|
||||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||||
} else {
|
} else {
|
||||||
cnd.and(View_user::getId, "=", SecurityUtil.getUserId());
|
cnd.and(View_user::getId, "=", SecurityUtil.getUserId());
|
||||||
|
|||||||
@@ -16,16 +16,20 @@ sm4cbc:
|
|||||||
keyHex: 00112233445566778899aabbccddeeff
|
keyHex: 00112233445566778899aabbccddeeff
|
||||||
ivHex: 0102030405060708090a0b0c0d0e0f10
|
ivHex: 0102030405060708090a0b0c0d0e0f10
|
||||||
|
|
||||||
jetty:
|
tomcat:
|
||||||
contextPath: /
|
contextPath: ""
|
||||||
threadpool:
|
# 容器错误响应不披露版本;Session Cookie 保持 HttpOnly。
|
||||||
idleTimeout: 60000
|
session:
|
||||||
minThreads: 10
|
cookie:
|
||||||
|
httponly: true
|
||||||
|
executor:
|
||||||
|
maxIdleTime: 60000
|
||||||
|
minSpareThreads: 10
|
||||||
maxThreads: 500
|
maxThreads: 500
|
||||||
page:
|
page:
|
||||||
403: /error/403.html
|
403: /__container_error
|
||||||
404: /error/404.html
|
404: /__container_error
|
||||||
500: /error/500.html
|
500: /__container_error
|
||||||
#结合ftp使用,或用nginx代理ftp路径
|
#结合ftp使用,或用nginx代理ftp路径
|
||||||
#staticPath: /Users/wizzer/temp/files
|
#staticPath: /Users/wizzer/temp/files
|
||||||
#开发模式静态资源
|
#开发模式静态资源
|
||||||
|
|||||||
@@ -510,10 +510,3 @@ CREATE TABLE IF NOT EXISTS `points_mall_schedule_user_points_record` (
|
|||||||
KEY `idx_points_mall_schedule_user_points_user` (`userId`),
|
KEY `idx_points_mall_schedule_user_points_user` (`userId`),
|
||||||
KEY `idx_points_mall_schedule_user_points_status` (`status`)
|
KEY `idx_points_mall_schedule_user_points_status` (`status`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分商城定时发放积分记录';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分商城定时发放积分记录';
|
||||||
|
|
||||||
ALTER TABLE sys_user
|
|
||||||
ADD COLUMN virtual_id VARCHAR(64) NULL COMMENT '虚拟用户ID,积分商城向供应商传递的用户标识',
|
|
||||||
ADD COLUMN virtual_org_id VARCHAR(255) NULL COMMENT '虚拟组织ID';
|
|
||||||
|
|
||||||
UPDATE sys_user SET virtual_id = MD5(CONCAT(id, '_', loginName, '_', salt))
|
|
||||||
where id is not null and loginName is not null and salt is not null;
|
|
||||||
@@ -14,7 +14,7 @@ var ioc={
|
|||||||
// 单个文件最大尺寸(大约的值,单位为字节,即 2097152 为 2M)
|
// 单个文件最大尺寸(大约的值,单位为字节,即 2097152 为 2M)
|
||||||
maxFileSize : 2097152,
|
maxFileSize : 2097152,
|
||||||
// 正则表达式匹配可以支持的文件名
|
// 正则表达式匹配可以支持的文件名
|
||||||
nameFilter : '^(.+[.])(gif|jpg|png|svg)$'
|
nameFilter : '(?i)^(.+[.])(gif|jpg|jpeg|png)$'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
imageUpload : {
|
imageUpload : {
|
||||||
@@ -32,7 +32,7 @@ var ioc={
|
|||||||
// 单个文件最大尺寸(大约的值,单位为字节,即 209715200 为 200M)
|
// 单个文件最大尺寸(大约的值,单位为字节,即 209715200 为 200M)
|
||||||
maxFileSize : 209715200,
|
maxFileSize : 209715200,
|
||||||
// 正则表达式匹配可以支持的文件名
|
// 正则表达式匹配可以支持的文件名
|
||||||
nameFilter : '^(.+[.])(gif||svg|jpg|png|jpeg|doc|docx|xls|xlsx|rar|zip|7z|txt|pdf|pptx|ppt|mp4)$'
|
nameFilter : '(?i)^(.+[.])(gif|jpg|png|jpeg|doc|docx|xls|xlsx|rar|zip|7z|txt|pdf|pptx|ppt|mp4)$'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fileUpload : {
|
fileUpload : {
|
||||||
|
|||||||
+1
-33
@@ -187,31 +187,6 @@ layout("/layouts/platform.html"){
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="生日"
|
|
||||||
v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<el-form-item prop="condolenceBirthday" label="生日">
|
|
||||||
<el-input
|
|
||||||
:value="formData.condolenceBirthday && $moment(formData.condolenceBirthday).isValid() ?$moment(formData.condolenceBirthday).format('YYYY-MM-DD') : ''"
|
|
||||||
show-word-limit placeholder="请输入生日" disabled></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="身份证号"
|
|
||||||
v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<el-form-item prop="condolenceIdCard" label="身份证号">
|
|
||||||
<el-input v-model="formData.condolenceIdCard" show-word-limit
|
|
||||||
placeholder="请输入身份证号" disabled></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="联系方式"
|
|
||||||
v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<el-form-item prop="condolenceMobile" label="联系方式">
|
|
||||||
<el-input v-model="formData.condolenceMobile" show-word-limit
|
|
||||||
placeholder="请输入联系方式" disabled></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="慰问类型"
|
<el-descriptions-item label="慰问类型"
|
||||||
v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
||||||
<el-form-item label="慰问类型" prop="condolenceTypeId">
|
<el-form-item label="慰问类型" prop="condolenceTypeId">
|
||||||
@@ -816,7 +791,6 @@ layout("/layouts/platform.html"){
|
|||||||
trigger: ["change", "blur"]
|
trigger: ["change", "blur"]
|
||||||
}, {pattern: /^([1-9]{1})(\d{15}|\d{18})$/, message: "请输入正确的银行卡号", trigger: "blur"}],
|
}, {pattern: /^([1-9]{1})(\d{15}|\d{18})$/, message: "请输入正确的银行卡号", trigger: "blur"}],
|
||||||
bankOfDeposit: [{required: true, message: "请填写开户行", trigger: ["change", "blur"]}],
|
bankOfDeposit: [{required: true, message: "请填写开户行", trigger: ["change", "blur"]}],
|
||||||
condolenceMobile: [{pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号码", trigger: "blur"}],
|
|
||||||
condolenceTime: [{required: true, message: "请选择慰问时间", trigger: ["change", "blur"]}],
|
condolenceTime: [{required: true, message: "请选择慰问时间", trigger: ["change", "blur"]}],
|
||||||
// invoiceNumber: [{required: true, message: "请填写发票张数", trigger: ["change", "blur"]}],
|
// invoiceNumber: [{required: true, message: "请填写发票张数", trigger: ["change", "blur"]}],
|
||||||
// invoice: [{required: true, message: "请填写发票号码", trigger: ["change", "blur"]}],
|
// invoice: [{required: true, message: "请填写发票号码", trigger: ["change", "blur"]}],
|
||||||
@@ -1187,10 +1161,7 @@ layout("/layouts/platform.html"){
|
|||||||
unionId,
|
unionId,
|
||||||
unionName,
|
unionName,
|
||||||
unionCode,
|
unionCode,
|
||||||
sex,
|
sex
|
||||||
birthday,
|
|
||||||
idCard,
|
|
||||||
mobile
|
|
||||||
} = user
|
} = user
|
||||||
this.$set(this.formData, "condolenceUserName", userName)
|
this.$set(this.formData, "condolenceUserName", userName)
|
||||||
this.$set(this.formData, "condolenceLoginName", loginName)
|
this.$set(this.formData, "condolenceLoginName", loginName)
|
||||||
@@ -1200,9 +1171,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.$set(this.formData, "condolenceUnionName", unionName)
|
this.$set(this.formData, "condolenceUnionName", unionName)
|
||||||
this.$set(this.formData, "condolenceUnionCode", unionCode)
|
this.$set(this.formData, "condolenceUnionCode", unionCode)
|
||||||
this.$set(this.formData, "condolenceSex", sex)
|
this.$set(this.formData, "condolenceSex", sex)
|
||||||
this.$set(this.formData, "condolenceBirthday", birthday)
|
|
||||||
this.$set(this.formData, "condolenceIdCard", idCard)
|
|
||||||
this.$set(this.formData, "condolenceMobile", mobile)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeChange(val) {
|
typeChange(val) {
|
||||||
|
|||||||
@@ -86,18 +86,6 @@ const unionReimburseInfo = {
|
|||||||
<span>{{ viewData.condolenceSex }}</span>
|
<span>{{ viewData.condolenceSex }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="生日" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<span>{{ viewData.condolenceBirthday && $moment(viewData.condolenceBirthday).isValid() ? $moment(viewData.condolenceBirthday).format('YYYY-MM-DD') : '' }}</span>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="身份证号" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<span>{{ viewData.condolenceIdCard }}</span>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="联系方式" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
|
||||||
<span>{{ viewData.condolenceMobile }}</span>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="慰问类型" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
<el-descriptions-item label="慰问类型" v-if="viewData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
||||||
<span>{{ viewData.typeName }}</span>
|
<span>{{ viewData.typeName }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|||||||
@@ -14,11 +14,19 @@ layout("/layouts/platform.html"){
|
|||||||
<el-option label="失败" :value="1"></el-option>
|
<el-option label="失败" :value="1"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</search-item>
|
</search-item>
|
||||||
|
<search-item label="成功订单">
|
||||||
|
<el-input clearable placeholder="请输入订单ID" v-model="pageForm.sucOrderIds"></el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="失败订单">
|
||||||
|
<el-input clearable placeholder="请输入订单ID" v-model="pageForm.failOrderIds"></el-input>
|
||||||
|
</search-item>
|
||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card class="mt10" shadow="never">
|
<el-card class="mt10" shadow="never">
|
||||||
<table-tool label="发票管理">
|
<table-tool label="发票管理">
|
||||||
|
<el-button @click="openApplyDialog" size="mini" type="success">开票申请</el-button>
|
||||||
|
<el-button @click="openOrderDialog" size="mini" type="primary">可开票订单</el-button>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
||||||
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
||||||
@@ -28,11 +36,13 @@ layout("/layouts/platform.html"){
|
|||||||
<el-tag :type="invoiceResultType(row.bSuccess)" size="mini">{{ invoiceResultName(row.bSuccess) }}</el-tag>
|
<el-tag :type="invoiceResultType(row.bSuccess)" size="mini">{{ invoiceResultName(row.bSuccess) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="340">
|
<el-table-column align="center" label="成功订单" min-width="220" prop="sucOrderIds" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" label="失败订单" min-width="220" prop="failOrderIds" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" label="失败原因" min-width="220" prop="failMsg" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" fixed="right" label="操作" width="220">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
<el-button @click="openOrderDialog(row.sucOrderIds)" size="mini" type="primary">开票成功列表</el-button>
|
<el-button @click="openInfoDialog(row)" size="mini" type="primary">发票明细</el-button>
|
||||||
<el-button @click="openInfoDialog(row)" size="mini">查看</el-button>
|
<el-button @click="openOrderDialog(row.sucOrderIds)" size="mini">成功订单</el-button>
|
||||||
<el-button v-if="Number(row.bSuccess) === 1" @click="retryInvoice(row.id)" :loading="retryLoading" size="mini" type="warning">重新获取发票</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -48,25 +58,120 @@ layout("/layouts/platform.html"){
|
|||||||
></el-pagination>
|
></el-pagination>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :close-on-click-modal="false" title="订单明细" :visible.sync="orderDialogVisible" top="5vh" width="90%">
|
<el-dialog :close-on-click-modal="false" title="开票申请" :visible.sync="applyDialogVisible" top="5vh" width="720px">
|
||||||
<el-table :data="orderList" border size="small" style="width: 100%" v-loading="orderLoading">
|
<el-form :model="applyForm" label-width="120px" size="small">
|
||||||
|
<el-form-item label="供应商" required>
|
||||||
|
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="applyForm.supplierId">
|
||||||
|
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单完成日期" required>
|
||||||
|
<el-date-picker
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
style="width: 100%"
|
||||||
|
type="daterange"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
v-model="applyDateRange"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单ID" required>
|
||||||
|
<el-input placeholder="多个订单ID用英文逗号分隔" type="textarea" v-model="applyForm.orderIds"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开票日期" required>
|
||||||
|
<el-date-picker placeholder="请选择开票日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="applyForm.invoiceDate"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="发票抬头">
|
||||||
|
<el-input clearable placeholder="请输入发票抬头" v-model="applyForm.invoiceTitle"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="纳税人识别号" required>
|
||||||
|
<el-input clearable placeholder="请输入纳税人识别号" v-model="applyForm.invoiceCode"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="发票地址" required>
|
||||||
|
<el-input clearable placeholder="请输入发票地址" v-model="applyForm.invoiceAddress"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系电话" required>
|
||||||
|
<el-input clearable placeholder="请输入联系电话" v-model="applyForm.invoiceContact"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="发票类型">
|
||||||
|
<el-select clearable placeholder="请选择发票类型" style="width: 100%" v-model="applyForm.invoiceType">
|
||||||
|
<el-option label="全电专票" :value="9"></el-option>
|
||||||
|
<el-option label="全电普票" :value="10"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开票内容">
|
||||||
|
<el-input clearable placeholder="请输入开票内容" v-model="applyForm.invoiceContent"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开户银行">
|
||||||
|
<el-input clearable placeholder="请输入开户银行" v-model="applyForm.bankName"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行账号">
|
||||||
|
<el-input clearable placeholder="请输入银行账号" v-model="applyForm.bankAccount"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input placeholder="请输入备注" type="textarea" v-model="applyForm.remark"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单积分合计">
|
||||||
|
<span>{{ orderTotalPoints }}</span>
|
||||||
|
<el-button @click="loadOrderTotalPoints" size="mini" style="margin-left: 12px">计算</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||||
|
<el-button @click="submitApply" :loading="applyLoading" type="primary">提交申请</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :close-on-click-modal="false" title="可开票订单" :visible.sync="orderDialogVisible" top="5vh" width="90%">
|
||||||
|
<el-form :inline="true" size="small" @submit.native.prevent>
|
||||||
|
<el-form-item label="供应商">
|
||||||
|
<el-select clearable filterable placeholder="供应商" style="width: 180px" v-model="orderForm.supplierId">
|
||||||
|
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单ID">
|
||||||
|
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="orderForm.orderId"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="完成日期">
|
||||||
|
<el-date-picker
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
style="width: 260px"
|
||||||
|
type="daterange"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
v-model="orderDateRange"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开票状态">
|
||||||
|
<el-select clearable placeholder="开票状态" style="width: 130px" v-model="orderForm.invoiceStatus">
|
||||||
|
<el-option label="未开票" :value="0"></el-option>
|
||||||
|
<el-option label="已开票" :value="1"></el-option>
|
||||||
|
<el-option label="开票中" :value="2"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="orderSearch" type="primary">查询</el-button>
|
||||||
|
<el-button @click="orderReset">重置</el-button>
|
||||||
|
<el-button @click="useOrdersForApply" type="success">用于开票</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table :data="orderList" @selection-change="orderSelectionChange" border size="small" style="width: 100%" v-loading="orderLoading">
|
||||||
|
<el-table-column align="center" type="selection" width="50"></el-table-column>
|
||||||
|
<el-table-column :index="orderIndexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
||||||
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="主订单号" min-width="170" prop="mainOrderId" show-overflow-tooltip></el-table-column>
|
|
||||||
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="订单状态" min-width="110">
|
<el-table-column align="center" label="用户ID" min-width="120" prop="userId" show-overflow-tooltip></el-table-column>
|
||||||
<template slot-scope="{row}">
|
<el-table-column align="center" label="完成时间" min-width="160" prop="orderCompleteTime"></el-table-column>
|
||||||
<el-tag :type="orderStatusType(row.orderState)" size="mini">{{ orderStateName(row.orderState) }}</el-tag>
|
<el-table-column align="center" label="订单总金额" min-width="110" prop="totalPrice"></el-table-column>
|
||||||
</template>
|
<el-table-column align="center" label="积分金额" min-width="110" prop="pointsPrice"></el-table-column>
|
||||||
</el-table-column>
|
<el-table-column align="center" label="退款积分" min-width="110" prop="refund"></el-table-column>
|
||||||
<el-table-column align="center" label="发票状态" min-width="100">
|
<el-table-column align="center" label="开票状态" min-width="100">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
<el-tag :type="invoiceStatusType(row.invoiceStatus)" size="mini">{{ invoiceStatusName(row.invoiceStatus) }}</el-tag>
|
<el-tag :type="invoiceStatusType(row.invoiceStatus)" size="mini">{{ invoiceStatusName(row.invoiceStatus) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="完成时间" min-width="160" prop="orderCompleteTime"></el-table-column>
|
|
||||||
<el-table-column align="center" label="实际消耗积分" min-width="110">
|
|
||||||
<template slot-scope="{row}">{{ (Number(row.pointsPrice || 0) - Number(row.refund || 0)).toFixed(2) }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="orderForm.pageNumber"
|
:current-page="orderForm.pageNumber"
|
||||||
@@ -79,30 +184,37 @@ layout("/layouts/platform.html"){
|
|||||||
style="margin-top: 16px; text-align: right"
|
style="margin-top: 16px; text-align: right"
|
||||||
></el-pagination>
|
></el-pagination>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<span style="margin-right: 20px">总消耗积分:{{ orderTotalPoints }}</span>
|
|
||||||
<el-button @click="orderDialogVisible = false">关闭</el-button>
|
<el-button @click="orderDialogVisible = false">关闭</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog :close-on-click-modal="false" title="发票明细列表" :visible.sync="infoDialogVisible" top="5vh" width="90%">
|
<el-dialog :close-on-click-modal="false" title="发票明细" :visible.sync="infoDialogVisible" top="5vh" width="90%">
|
||||||
<el-table :data="infoList" stripe size="small" style="width: 100%" v-loading="infoLoading">
|
<el-form :inline="true" size="small" @submit.native.prevent>
|
||||||
<el-table-column label="发票主ID" min-width="160" prop="mainId" show-overflow-tooltip></el-table-column>
|
<el-form-item label="发票号码">
|
||||||
<el-table-column label="发票号码" min-width="170" prop="invoiceId" show-overflow-tooltip></el-table-column>
|
<el-input clearable placeholder="发票号码" v-model="infoForm.invoiceId"></el-input>
|
||||||
<el-table-column label="发票代码" min-width="160" prop="invoiceCode" show-overflow-tooltip></el-table-column>
|
</el-form-item>
|
||||||
<el-table-column label="发票日期" min-width="140" prop="invoiceDate"></el-table-column>
|
<el-form-item label="发票代码">
|
||||||
<el-table-column label="发票裸价" min-width="130" prop="invoiceNakeAmount"></el-table-column>
|
<el-input clearable placeholder="发票代码" v-model="infoForm.invoiceCode"></el-input>
|
||||||
<el-table-column label="发票税率" min-width="110" prop="invoiceTaxRate"></el-table-column>
|
</el-form-item>
|
||||||
<el-table-column label="发票税额" min-width="130" prop="invoiceTaxAmount"></el-table-column>
|
<el-form-item label="发票日期">
|
||||||
<el-table-column label="价税合计" min-width="130" prop="invoiceAmount"></el-table-column>
|
<el-date-picker clearable placeholder="发票日期" type="date" value-format="yyyy-MM-dd" v-model="infoForm.invoiceDate"></el-date-picker>
|
||||||
<el-table-column label="发票类型" min-width="180">
|
</el-form-item>
|
||||||
<template slot-scope="{row}"><el-tag size="mini">{{ Number(row.invoiceType) === 9 ? '全电发票(增值税专用发票)' : Number(row.invoiceType) === 10 ? '全电发票(增值税普通发票)' : invoiceTypeName(row.invoiceType) }}</el-tag></template>
|
<el-form-item>
|
||||||
</el-table-column>
|
<el-button @click="infoSearch" type="primary">查询</el-button>
|
||||||
<el-table-column align="center" label="电子发票" width="110">
|
</el-form-item>
|
||||||
<template slot-scope="{row}"><el-button @click="previewInvoice(row)" size="mini" type="text">预览</el-button></template>
|
</el-form>
|
||||||
</el-table-column>
|
<el-table :data="infoList" border size="small" style="width: 100%" v-loading="infoLoading">
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="100">
|
<el-table-column :index="infoIndexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
||||||
<template slot-scope="{row}"><el-button @click="openInvoiceDetail(row)" size="mini" type="text">详情</el-button></template>
|
<el-table-column align="center" label="发票号码" min-width="150" prop="invoiceId" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" label="发票代码" min-width="130" prop="invoiceCode" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" label="发票日期" min-width="120" prop="invoiceDate"></el-table-column>
|
||||||
|
<el-table-column align="center" label="发票类型" min-width="110">
|
||||||
|
<template slot-scope="{row}">{{ invoiceTypeName(row.invoiceType) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="价税合计" min-width="110" prop="invoiceAmount"></el-table-column>
|
||||||
|
<el-table-column align="center" label="税额" min-width="100" prop="invoiceTaxAmount"></el-table-column>
|
||||||
|
<el-table-column align="center" label="纳税人识别号" min-width="160" prop="taxIdNumber" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" label="电子发票地址" min-width="220" prop="url" show-overflow-tooltip></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="infoForm.pageNumber"
|
:current-page="infoForm.pageNumber"
|
||||||
@@ -113,46 +225,9 @@ layout("/layouts/platform.html"){
|
|||||||
style="margin-top: 16px; text-align: right"
|
style="margin-top: 16px; text-align: right"
|
||||||
></el-pagination>
|
></el-pagination>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="retryInvoice(infoForm.mainId)" :loading="retryLoading" type="primary">重新获取发票</el-button>
|
|
||||||
<el-button @click="infoDialogVisible = false">关闭</el-button>
|
<el-button @click="infoDialogVisible = false">关闭</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog :close-on-click-modal="false" title="发票详情" :visible.sync="detailDialogVisible" append-to-body top="5vh" width="70%">
|
|
||||||
<el-card v-loading="detailLoading" shadow="never">
|
|
||||||
<el-descriptions :column="2" border size="small">
|
|
||||||
<el-descriptions-item label="发票主ID">{{ detailData.mainId || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票号码">{{ detailData.invoiceId || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票代码">{{ detailData.invoiceCode || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票日期">{{ detailData.invoiceDate || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票类型">
|
|
||||||
<el-tag size="mini" :type="Number(detailData.invoiceType) === 9 ? 'warning' : 'primary'">{{ Number(detailData.invoiceType) === 9 ? '全电发票(增值税专用发票)' : Number(detailData.invoiceType) === 10 ? '全电发票(增值税普通发票)' : invoiceTypeName(detailData.invoiceType) }}</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票状态"><el-tag size="mini" :type="Number(detailData.status) === 1 ? 'success' : Number(detailData.status) === 2 ? 'danger' : 'info'">{{ Number(detailData.status) === 1 ? '成功' : Number(detailData.status) === 2 ? '失败' : '未知' }}</el-tag></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票裸价"><span style="color: #409eff">¥{{ Number(detailData.invoiceNakeAmount || 0).toFixed(2) }}</span></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票税率">{{ detailData.invoiceTaxRate == null ? '-' : (Number(detailData.invoiceTaxRate) * 100).toFixed(2) + '%' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="发票税额"><span style="color: #409eff">¥{{ Number(detailData.invoiceTaxAmount || 0).toFixed(2) }}</span></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="价税合计" :span="3"><strong style="color: #f56c6c; font-size: 18px">¥{{ Number(detailData.invoiceAmount || 0).toFixed(2) }}</strong></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="备注" :span="2" v-if="detailData.remark">{{ detailData.remark }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="电子发票">
|
|
||||||
<template v-if="detailData.url || detailData.imageEncode">
|
|
||||||
<el-button @click="previewInvoice(detailData)" size="mini" type="text" icon="el-icon-view">预览PDF</el-button>
|
|
||||||
<el-link :href="detailData.url || detailData.imageEncode" :download="(detailData.invoiceId || '发票') + '.' + (detailData.fileType || 'pdf').toLowerCase()" type="success" :underline="false" icon="el-icon-download" style="margin-left: 16px">下载PDF</el-link>
|
|
||||||
</template>
|
|
||||||
<span v-else>暂无地址</span>
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</el-card>
|
|
||||||
<span slot="footer">
|
|
||||||
<el-button v-if="detailData.id && (Number(detailData.status) === 2 || !detailData.url)" @click="retryInvoice(detailData.mainId)" :loading="retryLoading" type="primary">重新获取发票</el-button>
|
|
||||||
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog :close-on-click-modal="false" title="PDF预览" :visible.sync="pdfDialogVisible" append-to-body width="80%" @closed="closePdfPreview">
|
|
||||||
<div v-loading="pdfLoading" style="height: 70vh">
|
|
||||||
<iframe v-if="pdfUrl" :src="pdfUrl" title="发票PDF预览" style="width: 100%; height: 100%; border: 0"></iframe>
|
|
||||||
</div>
|
|
||||||
<span slot="footer"><el-button @click="pdfDialogVisible = false">关闭</el-button></span>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script nonce="${cspNonce!}">
|
<script nonce="${cspNonce!}">
|
||||||
@@ -161,6 +236,7 @@ layout("/layouts/platform.html"){
|
|||||||
mixins: [initTableMixins],
|
mixins: [initTableMixins],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
supplierList: [],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
pageForm: {
|
pageForm: {
|
||||||
@@ -168,28 +244,48 @@ layout("/layouts/platform.html"){
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
totalCount: 0,
|
totalCount: 0,
|
||||||
settlementId: null,
|
settlementId: null,
|
||||||
bSuccess: null
|
bSuccess: null,
|
||||||
|
sucOrderIds: null,
|
||||||
|
failOrderIds: null,
|
||||||
|
failMsg: null
|
||||||
},
|
},
|
||||||
|
applyDialogVisible: false,
|
||||||
|
applyLoading: false,
|
||||||
|
applyDateRange: [],
|
||||||
orderTotalPoints: 0,
|
orderTotalPoints: 0,
|
||||||
|
applyForm: this.emptyApplyForm(),
|
||||||
orderDialogVisible: false,
|
orderDialogVisible: false,
|
||||||
orderLoading: false,
|
orderLoading: false,
|
||||||
orderDateRange: [],
|
orderDateRange: [],
|
||||||
orderList: [],
|
orderList: [],
|
||||||
|
orderSelections: [],
|
||||||
orderForm: this.emptyOrderForm(),
|
orderForm: this.emptyOrderForm(),
|
||||||
infoDialogVisible: false,
|
infoDialogVisible: false,
|
||||||
infoLoading: false,
|
infoLoading: false,
|
||||||
infoList: [],
|
infoList: [],
|
||||||
infoForm: this.emptyInfoForm(),
|
infoForm: this.emptyInfoForm()
|
||||||
detailDialogVisible: false,
|
|
||||||
detailLoading: false,
|
|
||||||
retryLoading: false,
|
|
||||||
pdfDialogVisible: false,
|
|
||||||
pdfLoading: false,
|
|
||||||
pdfUrl: null,
|
|
||||||
detailData: {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
emptyApplyForm() {
|
||||||
|
return {
|
||||||
|
supplierId: null,
|
||||||
|
orderIds: null,
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
invoiceDate: null,
|
||||||
|
invoiceTitle: null,
|
||||||
|
invoiceCode: null,
|
||||||
|
invoiceAddress: null,
|
||||||
|
invoiceContact: null,
|
||||||
|
invoiceType: 10,
|
||||||
|
invoiceContent: null,
|
||||||
|
remark: null,
|
||||||
|
bankAccount: null,
|
||||||
|
registeredAddress: null,
|
||||||
|
bankName: null
|
||||||
|
}
|
||||||
|
},
|
||||||
emptyOrderForm() {
|
emptyOrderForm() {
|
||||||
return {
|
return {
|
||||||
pageNumber: 1,
|
pageNumber: 1,
|
||||||
@@ -199,7 +295,7 @@ layout("/layouts/platform.html"){
|
|||||||
orderId: null,
|
orderId: null,
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
invoiceStatus: null
|
invoiceStatus: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emptyInfoForm() {
|
emptyInfoForm() {
|
||||||
@@ -247,21 +343,79 @@ layout("/layouts/platform.html"){
|
|||||||
this.pageForm.pageNumber = 1
|
this.pageForm.pageNumber = 1
|
||||||
this.pageData()
|
this.pageData()
|
||||||
},
|
},
|
||||||
|
async loadSuppliers() {
|
||||||
|
const resp = await this.$axios.post(loc() + "/supplierList")
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.supplierList = resp.data || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openApplyDialog() {
|
||||||
|
this.applyForm = this.emptyApplyForm()
|
||||||
|
this.applyDateRange = []
|
||||||
|
this.orderTotalPoints = 0
|
||||||
|
this.applyDialogVisible = true
|
||||||
|
},
|
||||||
|
syncApplyDateRange() {
|
||||||
|
this.applyForm.startDate = this.applyDateRange && this.applyDateRange.length ? this.applyDateRange[0] : null
|
||||||
|
this.applyForm.endDate = this.applyDateRange && this.applyDateRange.length ? this.applyDateRange[1] : null
|
||||||
|
},
|
||||||
|
async loadOrderTotalPoints() {
|
||||||
|
this.syncApplyDateRange()
|
||||||
|
if (!this.applyForm.supplierId || !this.applyForm.orderIds) {
|
||||||
|
this.notifyWarning("请先选择供应商并填写订单ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const resp = await this.$axios.post(loc() + "/orderTotalPoints", {
|
||||||
|
supplierId: this.applyForm.supplierId,
|
||||||
|
orderId: this.applyForm.orderIds,
|
||||||
|
startDate: this.applyForm.startDate,
|
||||||
|
endDate: this.applyForm.endDate,
|
||||||
|
invoiceStatus: 0
|
||||||
|
})
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.orderTotalPoints = resp.data || 0
|
||||||
|
} else {
|
||||||
|
this.notifyWarning(resp.msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async submitApply() {
|
||||||
|
this.syncApplyDateRange()
|
||||||
|
this.applyLoading = true
|
||||||
|
const resp = await this.$axios.post(loc() + "/applyInvoice", this.applyForm)
|
||||||
|
this.applyLoading = false
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.notifySuccess(resp.data || "开票申请成功")
|
||||||
|
this.applyDialogVisible = false
|
||||||
|
this.pageData()
|
||||||
|
} else {
|
||||||
|
this.notifyWarning(resp.msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
openOrderDialog(orderIds) {
|
openOrderDialog(orderIds) {
|
||||||
this.orderDialogVisible = true
|
this.orderDialogVisible = true
|
||||||
this.orderForm = this.emptyOrderForm()
|
this.orderForm = this.emptyOrderForm()
|
||||||
this.orderDateRange = []
|
this.orderDateRange = []
|
||||||
this.orderList = []
|
if (typeof orderIds === "string" && orderIds) {
|
||||||
this.orderTotalPoints = 0
|
|
||||||
if (typeof orderIds !== "string" || !orderIds.trim()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.orderForm.orderId = orderIds
|
this.orderForm.orderId = orderIds
|
||||||
|
this.orderForm.invoiceStatus = null
|
||||||
|
}
|
||||||
|
this.orderPageData()
|
||||||
|
},
|
||||||
|
syncOrderDateRange() {
|
||||||
|
this.orderForm.startDate = this.orderDateRange && this.orderDateRange.length ? this.orderDateRange[0] : null
|
||||||
|
this.orderForm.endDate = this.orderDateRange && this.orderDateRange.length ? this.orderDateRange[1] : null
|
||||||
|
},
|
||||||
|
orderSearch() {
|
||||||
|
this.orderForm.pageNumber = 1
|
||||||
|
this.orderPageData()
|
||||||
|
},
|
||||||
|
orderReset() {
|
||||||
|
this.orderForm = this.emptyOrderForm()
|
||||||
|
this.orderDateRange = []
|
||||||
this.orderPageData()
|
this.orderPageData()
|
||||||
this.loadOrderTotalPoints()
|
|
||||||
},
|
},
|
||||||
async orderPageData() {
|
async orderPageData() {
|
||||||
if (!this.orderForm.orderId) return
|
this.syncOrderDateRange()
|
||||||
this.orderLoading = true
|
this.orderLoading = true
|
||||||
const resp = await this.$axios.post(loc() + "/orderPage", this.orderForm)
|
const resp = await this.$axios.post(loc() + "/orderPage", this.orderForm)
|
||||||
this.orderLoading = false
|
this.orderLoading = false
|
||||||
@@ -281,77 +435,27 @@ layout("/layouts/platform.html"){
|
|||||||
this.orderForm.pageNumber = 1
|
this.orderForm.pageNumber = 1
|
||||||
this.orderPageData()
|
this.orderPageData()
|
||||||
},
|
},
|
||||||
async loadOrderTotalPoints() {
|
orderSelectionChange(rows) {
|
||||||
const resp = await this.$axios.post(loc() + "/orderTotalPoints", this.orderForm)
|
this.orderSelections = rows || []
|
||||||
if (resp.code === 0) this.orderTotalPoints = resp.data || 0
|
|
||||||
else this.notifyWarning(resp.msg)
|
|
||||||
},
|
},
|
||||||
async openInvoiceDetail(row) {
|
useOrdersForApply() {
|
||||||
this.detailData = {}
|
if (!this.orderSelections.length) {
|
||||||
this.detailDialogVisible = true
|
this.notifyWarning("请先选择订单")
|
||||||
this.detailLoading = true
|
|
||||||
try {
|
|
||||||
const resp = await this.$axios.post(loc() + "/infoDetail", { id: row.id })
|
|
||||||
if (resp.code === 0 && resp.data) this.detailData = resp.data
|
|
||||||
else this.notifyWarning(resp.msg || "发票详情不存在")
|
|
||||||
} finally {
|
|
||||||
this.detailLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async retryInvoice(mainId) {
|
|
||||||
if (!mainId || this.retryLoading) return
|
|
||||||
this.retryLoading = true
|
|
||||||
try {
|
|
||||||
const resp = await this.$axios.post(loc() + "/retryInvoice", { mainId })
|
|
||||||
if (resp.code !== 0) this.notifyWarning(resp.msg || "重新获取发票失败")
|
|
||||||
else this.$message.success("发票已重新获取")
|
|
||||||
await this.pageData()
|
|
||||||
if (this.infoDialogVisible && this.infoForm.mainId === mainId) await this.infoPageData()
|
|
||||||
if (this.detailDialogVisible && this.detailData.mainId === mainId) {
|
|
||||||
await this.openInvoiceDetail({ id: this.detailData.id })
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.notifyWarning(e.message || "重新获取发票失败")
|
|
||||||
} finally {
|
|
||||||
this.retryLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async previewInvoice(row) {
|
|
||||||
const path = row.url || row.imageEncode
|
|
||||||
if (!path) {
|
|
||||||
this.notifyWarning("暂无可预览的发票文件")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ((row.fileType || "pdf").toLowerCase() !== "pdf") {
|
const first = this.orderSelections[0]
|
||||||
this.$commonUtil.previewFile({ suffix: row.fileType.toLowerCase(), downloadPath: path, name: row.invoiceId || "发票" })
|
this.applyForm = this.emptyApplyForm()
|
||||||
return
|
this.applyForm.supplierId = first.supplierId
|
||||||
}
|
this.applyForm.orderIds = this.orderSelections.map((item) => item.orderId).join(",")
|
||||||
if (this.pdfLoading) return
|
this.applyForm.invoiceDate = new Date().toISOString().slice(0, 10)
|
||||||
this.closePdfPreview()
|
this.applyDateRange = [this.orderForm.startDate, this.orderForm.endDate].filter(Boolean)
|
||||||
this.pdfDialogVisible = true
|
this.orderDialogVisible = false
|
||||||
this.pdfLoading = true
|
this.applyDialogVisible = true
|
||||||
try {
|
this.loadOrderTotalPoints()
|
||||||
const response = await fetch(path, { credentials: "same-origin" })
|
|
||||||
if (!response.ok) throw new Error("获取发票文件失败")
|
|
||||||
const bytes = await response.arrayBuffer()
|
|
||||||
const signature = String.fromCharCode.apply(null, new Uint8Array(bytes, 0, Math.min(5, bytes.byteLength)))
|
|
||||||
if (signature !== "%PDF-") throw new Error("返回内容不是有效的PDF文件")
|
|
||||||
if (this.pdfDialogVisible) this.pdfUrl = URL.createObjectURL(new Blob([bytes], { type: "application/pdf" }))
|
|
||||||
} catch (e) {
|
|
||||||
this.notifyWarning(e.message || "发票预览失败")
|
|
||||||
this.pdfDialogVisible = false
|
|
||||||
} finally {
|
|
||||||
this.pdfLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
closePdfPreview() {
|
|
||||||
if (this.pdfUrl) URL.revokeObjectURL(this.pdfUrl)
|
|
||||||
this.pdfUrl = null
|
|
||||||
},
|
},
|
||||||
openInfoDialog(row) {
|
openInfoDialog(row) {
|
||||||
this.infoForm = this.emptyInfoForm()
|
this.infoForm = this.emptyInfoForm()
|
||||||
this.infoForm.mainId = row.id
|
this.infoForm.mainId = row.id
|
||||||
this.infoList = []
|
|
||||||
this.infoDialogVisible = true
|
this.infoDialogVisible = true
|
||||||
this.infoPageData()
|
this.infoPageData()
|
||||||
},
|
},
|
||||||
@@ -366,7 +470,6 @@ layout("/layouts/platform.html"){
|
|||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
this.infoList = resp.data.list || []
|
this.infoList = resp.data.list || []
|
||||||
this.infoForm.totalCount = resp.data.totalCount || 0
|
this.infoForm.totalCount = resp.data.totalCount || 0
|
||||||
this.pageData()
|
|
||||||
} else {
|
} else {
|
||||||
this.notifyWarning(resp.msg)
|
this.notifyWarning(resp.msg)
|
||||||
}
|
}
|
||||||
@@ -376,18 +479,10 @@ layout("/layouts/platform.html"){
|
|||||||
this.infoPageData()
|
this.infoPageData()
|
||||||
},
|
},
|
||||||
invoiceResultName(value) {
|
invoiceResultName(value) {
|
||||||
return value == null ? "开票中" : Number(value) === 0 ? "成功" : "失败"
|
return Number(value) === 0 ? "成功" : "失败"
|
||||||
},
|
},
|
||||||
invoiceResultType(value) {
|
invoiceResultType(value) {
|
||||||
return value == null ? "warning" : Number(value) === 0 ? "success" : "danger"
|
return Number(value) === 0 ? "success" : "danger"
|
||||||
},
|
|
||||||
orderStateName(value) {
|
|
||||||
const map = { 0: "待付款", 1: "已支付", 2: "进行中", 3: "已取消", 4: "已签收", 5: "已完成", 6: "换货", 7: "退货", 8: "已废除" }
|
|
||||||
return map[value] || "-"
|
|
||||||
},
|
|
||||||
orderStatusType(value) {
|
|
||||||
const map = { 0: "info", 1: "primary", 2: "warning", 3: "danger", 4: "primary", 5: "success", 6: "warning", 7: "danger", 8: "info" }
|
|
||||||
return map[value] || "info"
|
|
||||||
},
|
},
|
||||||
invoiceStatusName(value) {
|
invoiceStatusName(value) {
|
||||||
const map = { 0: "未开票", 1: "已开票", 2: "开票中" }
|
const map = { 0: "未开票", 1: "已开票", 2: "开票中" }
|
||||||
@@ -403,11 +498,8 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.loadSuppliers()
|
||||||
this.pageData()
|
this.pageData()
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.pdfDialogVisible = false
|
|
||||||
this.closePdfPreview()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,74 +3,44 @@ layout("/layouts/platform.html"){
|
|||||||
#-->
|
#-->
|
||||||
|
|
||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<el-card :body-style="{ paddingBottom: '2px' }" shadow="never">
|
<el-card shadow="never">
|
||||||
<el-form label-width="96px" @submit.native.prevent>
|
<search @search="doSearch">
|
||||||
<el-row :gutter="8">
|
<search-item label="供应商">
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
|
||||||
<el-form-item label="供应商">
|
|
||||||
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="pageForm.supplierId">
|
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="pageForm.supplierId">
|
||||||
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
|
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</search-item>
|
||||||
</el-col>
|
<search-item label="订单ID">
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="pageForm.orderId"></el-input>
|
||||||
<el-form-item label="起始日期">
|
</search-item>
|
||||||
|
<search-item label="用户ID">
|
||||||
|
<el-input clearable placeholder="请输入用户ID" v-model="pageForm.userId"></el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="起始日期">
|
||||||
<el-date-picker clearable placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.startDate"></el-date-picker>
|
<el-date-picker clearable placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.startDate"></el-date-picker>
|
||||||
</el-form-item>
|
</search-item>
|
||||||
</el-col>
|
<search-item label="结束日期">
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
|
||||||
<el-form-item label="结束日期">
|
|
||||||
<el-date-picker clearable placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.endDate"></el-date-picker>
|
<el-date-picker clearable placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.endDate"></el-date-picker>
|
||||||
</el-form-item>
|
</search-item>
|
||||||
</el-col>
|
<search-item label="对账状态">
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
|
||||||
<el-form-item label="对账类型">
|
|
||||||
<el-select clearable placeholder="请选择对账类型" style="width: 100%" v-model="pageForm.reconciliationType">
|
|
||||||
<el-option label="正常订单对账" :value="1"></el-option>
|
|
||||||
<el-option label="历史异常订单对账" :value="2"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
|
||||||
<el-form-item label="发票状态">
|
|
||||||
<el-select clearable placeholder="请选择发票状态" style="width: 100%" v-model="pageForm.invoiceStatus">
|
|
||||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in invoiceStatusOptions"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :lg="4" :md="12" :xs="24">
|
|
||||||
<el-form-item label="对账状态">
|
|
||||||
<el-select clearable placeholder="请选择对账状态" style="width: 100%" v-model="pageForm.reconciliationStatus">
|
<el-select clearable placeholder="请选择对账状态" style="width: 100%" v-model="pageForm.reconciliationStatus">
|
||||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in reconciliationStatusOptions"></el-option>
|
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in reconciliationStatusOptions"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</search-item>
|
||||||
</el-col>
|
<search-item label="发票状态">
|
||||||
<el-col :lg="6" :md="24" :xs="24">
|
<el-select clearable placeholder="请选择发票状态" style="width: 100%" v-model="pageForm.invoiceStatus">
|
||||||
<el-form-item label="订单ID">
|
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in invoiceStatusOptions"></el-option>
|
||||||
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="pageForm.orderId"></el-input>
|
</el-select>
|
||||||
</el-form-item>
|
</search-item>
|
||||||
</el-col>
|
</search>
|
||||||
<el-col :lg="12" :md="24" :xs="24">
|
|
||||||
<el-form-item label-width="16px">
|
|
||||||
<el-button @click="doSearch" native-type="button" type="primary">查询</el-button>
|
|
||||||
<el-button @click="resetSearch" native-type="button">重置</el-button>
|
|
||||||
<el-button @click="openReconcileDialog" native-type="button" type="success">对账</el-button>
|
|
||||||
<el-button
|
|
||||||
v-if="pageForm.reconciliationStatus === 1 && hasSearched && pageForm.invoiceStatus === 0"
|
|
||||||
@click="openApplyDialog"
|
|
||||||
native-type="button"
|
|
||||||
type="warning"
|
|
||||||
>开票申请</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card class="mt10" shadow="never">
|
<el-card class="mt10" shadow="never">
|
||||||
<table-tool label="对账订单列表"></table-tool>
|
<table-tool label="对账订单列表">
|
||||||
<el-table ref="tableRef" :data="tableData" @selection-change="selectionChange" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
<el-button @click="openReconcileDialog" size="mini" type="success">对账</el-button>
|
||||||
<el-table-column align="center" type="selection" width="50"></el-table-column>
|
<el-button @click="openRecordDialog" size="mini" type="primary">对账记录</el-button>
|
||||||
|
</table-tool>
|
||||||
|
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
||||||
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
||||||
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
||||||
@@ -117,43 +87,36 @@ layout("/layouts/platform.html"){
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :close-on-click-modal="false" title="确认对账" :visible.sync="reconcileDialogVisible" width="480px">
|
<el-dialog :close-on-click-modal="false" title="确认对账" :visible.sync="reconcileDialogVisible" width="480px">
|
||||||
<el-alert :closable="false" show-icon style="margin-bottom: 16px" :title="reconcileSelectionCount ? '本次仅对已勾选的 ' + reconcileSelectionCount + ' 笔订单执行对账。' : '您尚未勾选订单,本次将对当前查询条件下所有符合对账条件的订单执行对账(包含其他分页)。请确认对账范围。'" :type="reconcileSelectionCount ? 'info' : 'warning'"></el-alert>
|
<el-form label-width="100px" size="small">
|
||||||
<el-descriptions :column="1" border size="small">
|
<el-form-item label="供应商">
|
||||||
<el-descriptions-item label="本次对账金额">{{ reconcilePointsTotal }}</el-descriptions-item>
|
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="reconcileForm.supplierId">
|
||||||
</el-descriptions>
|
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
|
||||||
<el-alert :closable="false" show-icon style="margin-top: 16px" title="请记录当前对账积分金额,确认对账后该数值将不再展示。" type="warning"></el-alert>
|
</el-select>
|
||||||
<span slot="footer">
|
|
||||||
<el-button @click="reconcileDialogVisible = false">取消</el-button>
|
|
||||||
<el-button @click="executeReconciliation" :loading="executeLoading" type="primary">确认对账</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog :close-on-click-modal="false" title="开票申请" :visible.sync="applyDialogVisible" top="5vh" width="720px">
|
|
||||||
<el-alert :closable="false" show-icon type="info" style="margin-bottom: 16px"
|
|
||||||
:title="applySelectionCount ? '本次仅为已勾选的 ' + applySelectionCount + ' 笔订单申请开票。' : '未勾选订单,本次将为当前查询条件下的全部可开票订单申请开票(包含其他分页)。'"></el-alert>
|
|
||||||
<el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="120px" size="small">
|
|
||||||
<el-form-item label="开票日期" prop="invoiceDate">
|
|
||||||
<el-date-picker placeholder="请选择开票日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="applyForm.invoiceDate"></el-date-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="发票抬头" prop="invoiceTitle" required>
|
<el-form-item label="对账类型">
|
||||||
<el-input clearable placeholder="请输入发票抬头" v-model="applyForm.invoiceTitle"></el-input>
|
<el-select placeholder="请选择对账类型" style="width: 100%" v-model="reconcileForm.reconciliationType">
|
||||||
|
<el-option label="正常订单对账" :value="1"></el-option>
|
||||||
|
<el-option label="历史异常订单对账" :value="2"></el-option>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="纳税人识别号" prop="taxIdNumber" required>
|
<el-form-item label="起始日期">
|
||||||
<el-input clearable placeholder="请输入纳税人识别号" v-model="applyForm.taxIdNumber"></el-input>
|
<el-date-picker placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="reconcileForm.startDate"></el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="开户地址" prop="invoiceAddress" required>
|
<el-form-item label="结束日期">
|
||||||
<el-input clearable placeholder="请输入发票地址" v-model="applyForm.invoiceAddress"></el-input>
|
<el-date-picker placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="reconcileForm.endDate"></el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="联系电话" prop="invoiceContact" required>
|
<el-form-item label="订单ID">
|
||||||
<el-input clearable maxlength="11" placeholder="请输入联系电话" v-model="applyForm.invoiceContact"></el-input>
|
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="reconcileForm.orderId"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="发票类型" prop="invoiceType" required>
|
<el-form-item label="积分合计">
|
||||||
<dict-select clearable code="invoice_type" placeholder="请选择发票类型" style="width: 100%" v-model="applyForm.invoiceType"></dict-select>
|
<span>{{ reconcilePointsTotal }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<el-alert :closable="false" show-icon title="确认后订单将更新为已对账或对账异常,并生成对账记录。" type="warning"></el-alert>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
<el-button @click="reconcileDialogVisible = false">取消</el-button>
|
||||||
<el-button @click="submitApply" :loading="applyLoading" type="primary">确认开票</el-button>
|
<el-button @click="loadPointsTotal" :loading="pointsTotalLoading">计算金额</el-button>
|
||||||
|
<el-button @click="executeReconciliation" :loading="executeLoading" type="primary">确认对账</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
@@ -246,10 +209,6 @@ layout("/layouts/platform.html"){
|
|||||||
supplierList: [],
|
supplierList: [],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
selections: [],
|
|
||||||
lastQuery: null,
|
|
||||||
reconcileSelectionCount: 0,
|
|
||||||
hasSearched: false,
|
|
||||||
pageForm: {
|
pageForm: {
|
||||||
pageNumber: 1,
|
pageNumber: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -259,7 +218,6 @@ layout("/layouts/platform.html"){
|
|||||||
userId: null,
|
userId: null,
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
reconciliationType: null,
|
|
||||||
reconciliationStatus: null,
|
reconciliationStatus: null,
|
||||||
invoiceStatus: null
|
invoiceStatus: null
|
||||||
},
|
},
|
||||||
@@ -274,38 +232,6 @@ layout("/layouts/platform.html"){
|
|||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null
|
endDate: null
|
||||||
},
|
},
|
||||||
applyDialogVisible: false,
|
|
||||||
applyLoading: false,
|
|
||||||
applyScope: {},
|
|
||||||
applySelectionCount: 0,
|
|
||||||
applyForm: {
|
|
||||||
invoiceDate: [new Date().getFullYear(), String(new Date().getMonth() + 1).padStart(2, "0"), String(new Date().getDate()).padStart(2, "0")].join("-"),
|
|
||||||
invoiceTitle: "测试工会(开发测试)",
|
|
||||||
taxIdNumber: "91320100MA00000000",
|
|
||||||
invoiceAddress: "江苏省南京市测试路1号(开发测试)",
|
|
||||||
invoiceContact: "13800000000",
|
|
||||||
invoiceType: 10
|
|
||||||
},
|
|
||||||
applyRules: {
|
|
||||||
invoiceDate: [{ required: true, message: "请选择开票日期", trigger: "change" }],
|
|
||||||
invoiceTitle: [{ required: true, message: "请输入发票抬头", trigger: "blur" }],
|
|
||||||
taxIdNumber: [{ required: true, message: "请输入纳税人识别号", trigger: "blur" }],
|
|
||||||
invoiceAddress: [{ required: true, message: "请输入开户地址", trigger: "blur" }],
|
|
||||||
invoiceContact: [
|
|
||||||
{ required: true, message: "请输入联系电话", trigger: "blur" },
|
|
||||||
{
|
|
||||||
validator(rule, value, callback) {
|
|
||||||
if (value && !/^1[3-9]\d{9}$/.test(value)) {
|
|
||||||
callback(new Error("请输入正确的手机号码"))
|
|
||||||
} else {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
trigger: "blur"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
invoiceType: [{ required: true, message: "请选择发票类型", trigger: "change" }]
|
|
||||||
},
|
|
||||||
recordDialogVisible: false,
|
recordDialogVisible: false,
|
||||||
recordLoading: false,
|
recordLoading: false,
|
||||||
recordList: [],
|
recordList: [],
|
||||||
@@ -353,41 +279,14 @@ layout("/layouts/platform.html"){
|
|||||||
return index + 1 + (this.recordForm.pageNumber - 1) * this.recordForm.pageSize
|
return index + 1 + (this.recordForm.pageNumber - 1) * this.recordForm.pageSize
|
||||||
},
|
},
|
||||||
doSearch() {
|
doSearch() {
|
||||||
this.hasSearched = true
|
|
||||||
this.selections = []
|
|
||||||
this.pageForm.pageNumber = 1
|
this.pageForm.pageNumber = 1
|
||||||
this.pageData()
|
this.pageData()
|
||||||
},
|
},
|
||||||
resetSearch() {
|
|
||||||
this.pageForm = {
|
|
||||||
pageNumber: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
totalCount: 0,
|
|
||||||
supplierId: null,
|
|
||||||
orderId: null,
|
|
||||||
userId: null,
|
|
||||||
startDate: null,
|
|
||||||
endDate: null,
|
|
||||||
reconciliationType: null,
|
|
||||||
reconciliationStatus: null,
|
|
||||||
invoiceStatus: null
|
|
||||||
}
|
|
||||||
this.hasSearched = false
|
|
||||||
this.selections = []
|
|
||||||
this.pageData()
|
|
||||||
},
|
|
||||||
selectionChange(rows) {
|
|
||||||
this.selections = rows || []
|
|
||||||
},
|
|
||||||
async pageData() {
|
async pageData() {
|
||||||
this.tableLoading = true
|
this.tableLoading = true
|
||||||
const query = Object.assign({}, this.pageForm)
|
const resp = await this.$axios.post(loc() + "/pageData", this.pageForm)
|
||||||
const resp = await this.$axios.post(loc() + "/pageData", query)
|
|
||||||
this.tableLoading = false
|
this.tableLoading = false
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
this.lastQuery = query
|
|
||||||
this.selections = []
|
|
||||||
if (this.$refs.tableRef) this.$refs.tableRef.clearSelection()
|
|
||||||
this.tableData = resp.data.list || []
|
this.tableData = resp.data.list || []
|
||||||
this.pageForm.totalCount = resp.data.totalCount || 0
|
this.pageForm.totalCount = resp.data.totalCount || 0
|
||||||
} else {
|
} else {
|
||||||
@@ -409,67 +308,40 @@ layout("/layouts/platform.html"){
|
|||||||
this.supplierList = resp.data || []
|
this.supplierList = resp.data || []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async openReconcileDialog() {
|
openReconcileDialog() {
|
||||||
if (this.tableLoading || !this.lastQuery) {
|
|
||||||
this.notifyWarning("请先查询订单列表")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const query = this.lastQuery
|
|
||||||
this.reconcileSelectionCount = this.selections.length
|
|
||||||
this.reconcileForm = {
|
this.reconcileForm = {
|
||||||
supplierId: query.supplierId,
|
supplierId: this.pageForm.supplierId,
|
||||||
reconciliationType: query.reconciliationType,
|
reconciliationType: this.pageForm.reconciliationStatus === 2 ? 2 : 1,
|
||||||
orderId: this.selections.map(item => item.orderId).join(",") || null,
|
orderId: this.pageForm.orderId,
|
||||||
queryOrderId: query.orderId,
|
startDate: this.pageForm.startDate,
|
||||||
userId: query.userId,
|
endDate: this.pageForm.endDate
|
||||||
reconciliationStatus: query.reconciliationStatus,
|
|
||||||
invoiceStatus: query.invoiceStatus,
|
|
||||||
startDate: query.startDate,
|
|
||||||
endDate: query.endDate
|
|
||||||
}
|
}
|
||||||
this.reconcilePointsTotal = 0
|
this.reconcilePointsTotal = 0
|
||||||
if (!this.reconciliationParamsComplete()) {
|
|
||||||
this.notifyWarning("请选择供应商、对账类型和对账日期,并查询订单列表")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (await this.loadPointsTotal()) {
|
|
||||||
this.reconcileDialogVisible = true
|
this.reconcileDialogVisible = true
|
||||||
}
|
this.loadPointsTotal()
|
||||||
},
|
|
||||||
reconciliationParamsComplete() {
|
|
||||||
if (!this.reconcileForm.supplierId || !this.reconcileForm.reconciliationType) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!this.reconcileForm.startDate || !this.reconcileForm.endDate) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
},
|
||||||
async loadPointsTotal() {
|
async loadPointsTotal() {
|
||||||
if (!this.reconciliationParamsComplete()) {
|
if (!this.reconcileForm.supplierId || !this.reconcileForm.startDate || !this.reconcileForm.endDate || !this.reconcileForm.reconciliationType) {
|
||||||
return false
|
this.notifyWarning("请先选择供应商、对账类型和对账日期")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
this.pointsTotalLoading = true
|
this.pointsTotalLoading = true
|
||||||
try {
|
|
||||||
const resp = await this.$axios.post(loc() + "/pointsTotal", this.reconcileForm)
|
const resp = await this.$axios.post(loc() + "/pointsTotal", this.reconcileForm)
|
||||||
|
this.pointsTotalLoading = false
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
this.reconcilePointsTotal = resp.data || 0
|
this.reconcilePointsTotal = resp.data || 0
|
||||||
return true
|
} else {
|
||||||
}
|
|
||||||
this.notifyWarning(resp.msg)
|
this.notifyWarning(resp.msg)
|
||||||
return false
|
|
||||||
} finally {
|
|
||||||
this.pointsTotalLoading = false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async executeReconciliation() {
|
async executeReconciliation() {
|
||||||
if (!this.reconciliationParamsComplete()) {
|
if (!this.reconcileForm.supplierId || !this.reconcileForm.startDate || !this.reconcileForm.endDate || !this.reconcileForm.reconciliationType) {
|
||||||
this.notifyWarning("请先选择供应商、对账类型和对账日期,并查询订单列表")
|
this.notifyWarning("请先选择供应商、对账类型和对账日期")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.executeLoading = true
|
this.executeLoading = true
|
||||||
try {
|
|
||||||
const resp = await this.$axios.post(loc() + "/execute", this.reconcileForm)
|
const resp = await this.$axios.post(loc() + "/execute", this.reconcileForm)
|
||||||
|
this.executeLoading = false
|
||||||
if (resp.code === 0) {
|
if (resp.code === 0) {
|
||||||
this.notifySuccess(resp.data || "对账完成")
|
this.notifySuccess(resp.data || "对账完成")
|
||||||
this.reconcileDialogVisible = false
|
this.reconcileDialogVisible = false
|
||||||
@@ -477,66 +349,11 @@ layout("/layouts/platform.html"){
|
|||||||
} else {
|
} else {
|
||||||
this.notifyWarning(resp.msg)
|
this.notifyWarning(resp.msg)
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
this.executeLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openApplyDialog() {
|
|
||||||
if (this.tableLoading || !this.lastQuery) {
|
|
||||||
this.notifyWarning("请先查询订单列表")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const query = this.lastQuery
|
|
||||||
if (!query.supplierId || !query.startDate || !query.endDate || query.reconciliationStatus !== 1 || query.invoiceStatus !== 0) {
|
|
||||||
this.notifyWarning("请查询对账成功且未开票的订单")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.applySelectionCount = this.selections.length
|
|
||||||
this.applyScope = {
|
|
||||||
supplierId: query.supplierId,
|
|
||||||
startDate: query.startDate,
|
|
||||||
endDate: query.endDate,
|
|
||||||
queryOrderId: query.orderId,
|
|
||||||
userId: query.userId,
|
|
||||||
orderIds: this.selections.map(item => item.orderId).join(",") || null
|
|
||||||
}
|
|
||||||
this.applyForm = {
|
|
||||||
invoiceDate: [new Date().getFullYear(), String(new Date().getMonth() + 1).padStart(2, "0"), String(new Date().getDate()).padStart(2, "0")].join("-"),
|
|
||||||
invoiceTitle: "测试工会(开发测试)",
|
|
||||||
taxIdNumber: "91320100MA00000000",
|
|
||||||
invoiceAddress: "江苏省南京市测试路1号(开发测试)",
|
|
||||||
invoiceContact: "13800000000",
|
|
||||||
invoiceType: 10
|
|
||||||
}
|
|
||||||
this.applyDialogVisible = true
|
|
||||||
},
|
|
||||||
submitApply() {
|
|
||||||
this.$refs.applyFormRef.validate(async (valid) => {
|
|
||||||
if (!valid || this.applyLoading) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.applyLoading = true
|
|
||||||
try {
|
|
||||||
const params = Object.assign({}, this.applyForm, this.applyScope)
|
|
||||||
const resp = await this.$axios.post("/platform/zhgh/points-mall/invoice/applyInvoice", params)
|
|
||||||
if (resp.code === 0) {
|
|
||||||
this.notifySuccess(resp.data || "开票申请成功")
|
|
||||||
this.applyDialogVisible = false
|
|
||||||
this.selections = []
|
|
||||||
this.$refs.tableRef.clearSelection()
|
|
||||||
this.pageData()
|
|
||||||
} else {
|
|
||||||
this.notifyWarning(resp.msg)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.applyLoading = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
openRecordDialog() {
|
openRecordDialog() {
|
||||||
this.recordDialogVisible = true
|
this.recordDialogVisible = true
|
||||||
this.recordForm.supplierId = this.pageForm.supplierId
|
this.recordForm.supplierId = this.pageForm.supplierId
|
||||||
this.recordForm.orderId = null
|
this.recordForm.orderId = this.pageForm.orderId
|
||||||
this.recordPageData()
|
this.recordPageData()
|
||||||
},
|
},
|
||||||
recordSearch() {
|
recordSearch() {
|
||||||
|
|||||||
@@ -13,6 +13,25 @@ layout("/layouts/platform.html"){
|
|||||||
<search-item label="订单ID">
|
<search-item label="订单ID">
|
||||||
<el-input clearable placeholder="请输入订单ID" v-model="pageForm.orderId"></el-input>
|
<el-input clearable placeholder="请输入订单ID" v-model="pageForm.orderId"></el-input>
|
||||||
</search-item>
|
</search-item>
|
||||||
|
<search-item label="用户ID">
|
||||||
|
<el-input clearable placeholder="请输入用户ID" v-model="pageForm.userId"></el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="批次号">
|
||||||
|
<el-input clearable placeholder="请输入对账批次号" v-model="pageForm.batchNo"></el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="差异类型">
|
||||||
|
<el-select clearable placeholder="请选择差异类型" style="width: 100%" v-model="pageForm.diffType">
|
||||||
|
<el-option label="一致" :value="0"></el-option>
|
||||||
|
<el-option label="异常" :value="1"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="通知状态">
|
||||||
|
<el-select clearable placeholder="请选择通知状态" style="width: 100%" v-model="pageForm.noticeStatus">
|
||||||
|
<el-option label="未推送" :value="0"></el-option>
|
||||||
|
<el-option label="推送成功" :value="1"></el-option>
|
||||||
|
<el-option label="推送失败" :value="2"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
</search>
|
</search>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -20,10 +39,11 @@ layout("/layouts/platform.html"){
|
|||||||
<table-tool label="对账记录"></table-tool>
|
<table-tool label="对账记录"></table-tool>
|
||||||
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
|
||||||
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
|
||||||
|
<el-table-column align="center" label="批次号" min-width="170" prop="batchNo" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="供应商编码" min-width="130" prop="supplierId" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="供应商编码" min-width="130" prop="supplierId" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="用户工号" min-width="120" prop="loginname" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="用户ID" min-width="120" prop="userId" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column align="center" label="订单总金额(平台)" min-width="140" prop="pTotalPrice"></el-table-column>
|
<el-table-column align="center" label="订单总金额(平台)" min-width="140" prop="pTotalPrice"></el-table-column>
|
||||||
<el-table-column align="center" label="现金金额(平台)" min-width="130" prop="pCashAmount"></el-table-column>
|
<el-table-column align="center" label="现金金额(平台)" min-width="130" prop="pCashAmount"></el-table-column>
|
||||||
<el-table-column align="center" label="积分金额(平台)" min-width="130" prop="pPointsPrice"></el-table-column>
|
<el-table-column align="center" label="积分金额(平台)" min-width="130" prop="pPointsPrice"></el-table-column>
|
||||||
@@ -37,7 +57,18 @@ layout("/layouts/platform.html"){
|
|||||||
<el-tag :type="diffTypeTag(row.diffType)" size="mini">{{ diffTypeName(row.diffType) }}</el-tag>
|
<el-tag :type="diffTypeTag(row.diffType)" size="mini">{{ diffTypeName(row.diffType) }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="通知状态" min-width="110">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-tag :type="noticeStatusTag(row.noticeStatus)" size="mini">{{ noticeStatusName(row.noticeStatus) }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="推送次数" min-width="90" prop="pushTime"></el-table-column>
|
||||||
<el-table-column align="center" label="差异原因" min-width="240" prop="diffReason" show-overflow-tooltip></el-table-column>
|
<el-table-column align="center" label="差异原因" min-width="240" prop="diffReason" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column align="center" fixed="right" label="操作" width="90">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="openDetail(row)" size="mini" type="primary">查看</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="pageForm.pageNumber"
|
:current-page="pageForm.pageNumber"
|
||||||
@@ -56,7 +87,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-descriptions-item label="批次号">{{ currentRecord.batchNo || "-" }}</el-descriptions-item>
|
<el-descriptions-item label="批次号">{{ currentRecord.batchNo || "-" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="订单ID">{{ currentRecord.orderId || "-" }}</el-descriptions-item>
|
<el-descriptions-item label="订单ID">{{ currentRecord.orderId || "-" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="供应商">{{ currentRecord.supplierName || currentRecord.supplierId || "-" }}</el-descriptions-item>
|
<el-descriptions-item label="供应商">{{ currentRecord.supplierName || currentRecord.supplierId || "-" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="用户工号">{{ currentRecord.loginname || "-" }}</el-descriptions-item>
|
<el-descriptions-item label="用户ID">{{ currentRecord.userId || "-" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="平台总金额">{{ currentRecord.pTotalPrice || "0" }}</el-descriptions-item>
|
<el-descriptions-item label="平台总金额">{{ currentRecord.pTotalPrice || "0" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="对账总金额">{{ currentRecord.sTotalPrice || "0" }}</el-descriptions-item>
|
<el-descriptions-item label="对账总金额">{{ currentRecord.sTotalPrice || "0" }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="平台现金金额">{{ currentRecord.pCashAmount || "0" }}</el-descriptions-item>
|
<el-descriptions-item label="平台现金金额">{{ currentRecord.pCashAmount || "0" }}</el-descriptions-item>
|
||||||
@@ -90,7 +121,11 @@ layout("/layouts/platform.html"){
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
totalCount: 0,
|
totalCount: 0,
|
||||||
supplierId: null,
|
supplierId: null,
|
||||||
orderId: null
|
orderId: null,
|
||||||
|
userId: null,
|
||||||
|
diffType: null,
|
||||||
|
batchNo: null,
|
||||||
|
noticeStatus: null
|
||||||
},
|
},
|
||||||
detailDialogVisible: false,
|
detailDialogVisible: false,
|
||||||
currentRecord: null
|
currentRecord: null
|
||||||
|
|||||||
+1
-8
@@ -579,9 +579,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</van-action-sheet>
|
</van-action-sheet>
|
||||||
|
|
||||||
<van-field label="性别" v-model="formData.condolenceSex" readonly placeholder="自动带出"></van-field>
|
<van-field label="性别" v-model="formData.condolenceSex" readonly placeholder="自动带出"></van-field>
|
||||||
<van-field label="生日" :value="formatDateText(formData.condolenceBirthday)" readonly placeholder="自动带出"></van-field>
|
|
||||||
<van-field label="身份证号" v-model="formData.condolenceIdCard" readonly placeholder="自动带出"></van-field>
|
|
||||||
<van-field label="联系方式" v-model="formData.condolenceMobile" readonly placeholder="自动带出"></van-field>
|
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="formData.typeName"
|
v-model="formData.typeName"
|
||||||
@@ -1412,7 +1409,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
normalizeContactFields() {
|
normalizeContactFields() {
|
||||||
// 提交前裁剪联系方式空格,避免系统手机号带空格时后端格式校验失败。
|
// 提交前裁剪联系方式空格,避免系统手机号带空格时后端格式校验失败。
|
||||||
const fields = ["mobile", "condolenceMobile"]
|
const fields = ["mobile"]
|
||||||
fields.forEach((fieldName) => {
|
fields.forEach((fieldName) => {
|
||||||
if (this.formData[fieldName]) {
|
if (this.formData[fieldName]) {
|
||||||
this.$set(this.formData, fieldName, String(this.formData[fieldName]).trim())
|
this.$set(this.formData, fieldName, String(this.formData[fieldName]).trim())
|
||||||
@@ -2209,7 +2206,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
const selectedUser = this.condolenceOptions.find(user => user.id === o.value)
|
const selectedUser = this.condolenceOptions.find(user => user.id === o.value)
|
||||||
if (selectedUser) {
|
if (selectedUser) {
|
||||||
this.fillCondolenceUser(selectedUser)
|
this.fillCondolenceUser(selectedUser)
|
||||||
this.$set(this.formData, "condolenceMobile", selectedUser.mobile)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCondolenceTypeConfirm(o) {
|
onCondolenceTypeConfirm(o) {
|
||||||
@@ -2341,9 +2337,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$set(this.formData, "condolenceUnionName", user.unionName)
|
this.$set(this.formData, "condolenceUnionName", user.unionName)
|
||||||
this.$set(this.formData, "condolenceUnionCode", user.unionCode)
|
this.$set(this.formData, "condolenceUnionCode", user.unionCode)
|
||||||
this.$set(this.formData, "condolenceSex", user.sex)
|
this.$set(this.formData, "condolenceSex", user.sex)
|
||||||
this.$set(this.formData, "condolenceBirthday", user.birthday)
|
|
||||||
this.$set(this.formData, "condolenceIdCard", user.idCard)
|
|
||||||
this.$set(this.formData, "condolenceMobile", user.mobile)
|
|
||||||
},
|
},
|
||||||
// 查询慰问类型
|
// 查询慰问类型
|
||||||
queryCondolenceType() {
|
queryCondolenceType() {
|
||||||
|
|||||||
@@ -100,18 +100,6 @@ const UNION_REIMBURSE_INFO = {
|
|||||||
<div class="union-info-label">性别</div>
|
<div class="union-info-label">性别</div>
|
||||||
<div class="union-info-value">{{ viewData.condolenceSex }}</div>
|
<div class="union-info-value">{{ viewData.condolenceSex }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="union-info-row">
|
|
||||||
<div class="union-info-label">生日</div>
|
|
||||||
<div class="union-info-value">{{ formatDateText(viewData.condolenceBirthday) }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="union-info-row">
|
|
||||||
<div class="union-info-label">身份证号</div>
|
|
||||||
<div class="union-info-value">{{ viewData.condolenceIdCard }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="union-info-row">
|
|
||||||
<div class="union-info-label">联系方式</div>
|
|
||||||
<div class="union-info-value">{{ viewData.condolenceMobile }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="union-info-row">
|
<div class="union-info-row">
|
||||||
<div class="union-info-label">慰问类型</div>
|
<div class="union-info-label">慰问类型</div>
|
||||||
<div class="union-info-value">{{ viewData.typeName || viewData.condolenceTypeName }}</div>
|
<div class="union-info-value">{{ viewData.typeName || viewData.condolenceTypeName }}</div>
|
||||||
|
|||||||
@@ -146,12 +146,36 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.userPoints = resp.data || 0
|
this.userPoints = resp.data || 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openSupplier(item) {
|
async openSupplier(item) {
|
||||||
if (!item.supplierUrl) {
|
if (!item.supplierUrl) {
|
||||||
this.$toast("暂无跳转地址")
|
this.$toast("暂无跳转地址")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
window.location.href = item.supplierUrl
|
const userId = this.$store && this.$store.state.user ? this.$store.state.user.id : ""
|
||||||
|
if (!userId) {
|
||||||
|
this.$toast("获取用户信息失败,请重新登录后再试")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window.location.href = this.withSupplierQuery(item.supplierUrl, {
|
||||||
|
userId: userId
|
||||||
|
})
|
||||||
|
},
|
||||||
|
withSupplierQuery(url, params) {
|
||||||
|
const query = Object.keys(params)
|
||||||
|
.filter((key) => params[key] !== undefined && params[key] !== null && params[key] !== "")
|
||||||
|
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key]))
|
||||||
|
.join("&")
|
||||||
|
if (!query) {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
const hashIndex = url.indexOf("#")
|
||||||
|
if (hashIndex > -1) {
|
||||||
|
const base = url.slice(0, hashIndex)
|
||||||
|
const hash = url.slice(hashIndex)
|
||||||
|
const joiner = hash.indexOf("?") > -1 ? "&" : "?"
|
||||||
|
return base + hash + joiner + query
|
||||||
|
}
|
||||||
|
return url + (url.indexOf("?") > -1 ? "&" : "?") + query
|
||||||
},
|
},
|
||||||
onImgError(e) {
|
onImgError(e) {
|
||||||
e.target.src = this.defaultLogo
|
e.target.src = this.defaultLogo
|
||||||
|
|||||||
@@ -257,7 +257,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
return item ? item.class : "gray"
|
return item ? item.class : "gray"
|
||||||
},
|
},
|
||||||
getOrderStatusItem(value) {
|
getOrderStatusItem(value) {
|
||||||
if (Number(value) === 1) return { code: 1, name: "已支付", class: "blue" }
|
|
||||||
const list = this.normalTabList.concat(this.specialTabList)
|
const list = this.normalTabList.concat(this.specialTabList)
|
||||||
return list.find((tab) => Number(tab.code) === Number(value))
|
return list.find((tab) => Number(tab.code) === Number(value))
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
887dae22390914b7be8401e8ce87571d8f776eb6
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
71eb5eaecf2b7fd91d9dd7409a56314b9f2f132b3dffbb9e13ee56d0999b8c59
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
5bc042d969b2a8fae96441b439096181eb11bbce
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
0d9b4629144a1fd15ed01362ce0dc2c9c5246e4f57250dd95fb52dbbbb75c532
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-project</artifactId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>jetty-client</artifactId>
|
||||||
|
<version>9.4.57.v20241219-cug-patch1</version>
|
||||||
|
<name>Jetty :: Asynchronous HTTP Client</name>
|
||||||
|
<properties>
|
||||||
|
<bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
|
||||||
|
<jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc>
|
||||||
|
<spotbugs.onlyAnalyze>org.eclipse.client.*</spotbugs.onlyAnalyze>
|
||||||
|
</properties>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>unpack</id>
|
||||||
|
<phase>generate-test-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-test-policy</artifactId>
|
||||||
|
<version>${jetty-test-policy.version}</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<overWrite>true</overWrite>
|
||||||
|
<includes>**/*.keystore,**/*.pem</includes>
|
||||||
|
<outputDirectory>${jetty.test.policy.loc}</outputDirectory>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<minimizeJar>true</minimizeJar>
|
||||||
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
|
<shadedClassifierName>hybrid</shadedClassifierName>
|
||||||
|
<artifactSet>
|
||||||
|
<includes>
|
||||||
|
<include>org.eclipse.jetty:jetty-http</include>
|
||||||
|
<include>org.eclipse.jetty:jetty-io</include>
|
||||||
|
<include>org.eclipse.jetty:jetty-util</include>
|
||||||
|
</includes>
|
||||||
|
</artifactSet>
|
||||||
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.eclipse.jetty.http</pattern>
|
||||||
|
<shadedPattern>org.eclipse.jetty.client.shaded.http</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.eclipse.jetty.io</pattern>
|
||||||
|
<shadedPattern>org.eclipse.jetty.client.shaded.io</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>org.eclipse.jetty.util</pattern>
|
||||||
|
<shadedPattern>org.eclipse.jetty.client.shaded.util</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-http</artifactId>
|
||||||
|
<version>9.4.57.v20241219-cug-patch1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-io</artifactId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-jmx</artifactId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
<version>9.4.57.v20241219-cug-patch1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-security</artifactId>
|
||||||
|
<version>9.4.57.v20241219-cug-patch1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.kerby</groupId>
|
||||||
|
<artifactId>kerb-simplekdc</artifactId>
|
||||||
|
<version>2.1.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jline</groupId>
|
||||||
|
<artifactId>jline</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- transitive dependency defined as a range and we don't want that -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.minidev</groupId>
|
||||||
|
<artifactId>json-smart</artifactId>
|
||||||
|
<version>2.5.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.awaitility</groupId>
|
||||||
|
<artifactId>awaitility</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
024e0627736731cbd441931d50fcb22bf17f4cc0
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
989a013455688dc528a988c41514fbfece0e3354a54398af5a404cda582c94bd
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
d551472980052c26105c45dc476bfe07cc23dfb5
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
dcfe694ef6f27d9d6268e2fb135a1c9a7aabdfa55e7d738fc8df79f573086027
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
086fa31420e9a5a623cac7967b0b6de0674d93af
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
90058e595b73d85b96e192b7e6806098f83467680a95466974f445d6706ed682
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>jetty-project</artifactId>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>jetty-http</artifactId>
|
||||||
|
<version>9.4.57.v20241219-cug-patch1</version>
|
||||||
|
<name>Jetty :: Http Utility</name>
|
||||||
|
<properties>
|
||||||
|
<bundle-symbolic-name>${project.groupId}.http</bundle-symbolic-name>
|
||||||
|
<spotbugs.onlyAnalyze>org.eclipse.jetty.http.*</spotbugs.onlyAnalyze>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util</artifactId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-io</artifactId>
|
||||||
|
<version>9.4.57.v20241219</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||||
|
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>test-jar</id>
|
||||||
|
<goals>
|
||||||
|
<goal>test-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<finalName>${jmhjar.name}</finalName>
|
||||||
|
<shadeTestJar>true</shadeTestJar>
|
||||||
|
<artifactSet>
|
||||||
|
<includes>
|
||||||
|
<include>org.openjdk.jmh:jmh-core</include>
|
||||||
|
</includes>
|
||||||
|
</artifactSet>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>org.openjdk.jmh:jmh-core</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
f27754642c5b5e3b2e570669b7a1ceef613fc589
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
967fff3457fb62eb7485fe303cc4162edc1c02b15498c2f8401fbca263649ab8
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
0f398cff4f7ab827fecb9d4f657685b973512e35
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
770e71875fa37effaab5c11e932b9a52c2e019236062575b0403760242b0bf08
|
||||||
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user