From a4aa10f1bc384c209a6198dc68f6dd547e45c068 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 22 Apr 2025 00:29:57 +0800 Subject: [PATCH 01/39] =?UTF-8?q?=E7=83=AD=E6=9B=B4=E6=96=B0=E5=8C=85?= =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminAppMarketUpdateController.java | 56 ++++++ ...er.java => AppMarketUpdateController.java} | 2 +- .../service/AdminAppMarketUpdateService.java | 47 +++++ .../impl/AdminAppMarketUpdateServiceImpl.java | 186 +++++++++++++++++- .../modules/admin/AdminAppMarketUpdate.java | 3 + .../mall/common/pojo/dto/FileInfoDTO.java | 35 ++++ .../mall/common/utils/StringUtils.java | 64 ++++++ 7 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java rename mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/{AdminAppMarketUpdateController.java => AppMarketUpdateController.java} (97%) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java b/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java new file mode 100644 index 00000000..2dd15246 --- /dev/null +++ b/mall-admin/src/main/java/com/suisung/mall/admin/controller/admin/AdminAppMarketUpdateController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.admin.controller.admin; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.admin.service.AdminAppMarketUpdateService; +import com.suisung.mall.common.api.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + + +@Api(tags = "安卓应用市场 APP 版本检查") +@RestController +@RequestMapping("/admin/admin/app-market-update") +public class AdminAppMarketUpdateController { + + @Resource + private AdminAppMarketUpdateService adminAppMarketUpdateService; + + @ApiOperation(value = "安卓市场热更新记录搜索列表", notes = "安卓市场热更新记录搜索列表") + @RequestMapping(value = "/search/list", method = RequestMethod.POST) + public CommonResult searchList(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.searchListInAdmin(paramsJSON.getInt("marketId"), paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); + } + + @ApiOperation(value = "新增安卓市场热更新记录", notes = "新增安卓市场热更新记录") + @RequestMapping(value = "/add/new", method = RequestMethod.POST) + public CommonResult addNew(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.addNewInAdmin(paramsJSON); + } + + @ApiOperation(value = "修改安卓市场热更新记录", notes = "修改安卓市场热更新记录") + @RequestMapping(value = "/modify", method = RequestMethod.POST) + public CommonResult modify(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.modifyInAdmin(paramsJSON); + } + + @ApiOperation(value = "关闭安卓市场热更新记录", notes = "关闭安卓市场热更新记录") + @RequestMapping(value = "/enable-or-disable", method = RequestMethod.POST) + public CommonResult enableOrDisable(@RequestBody JSONObject paramsJSON) { + return adminAppMarketUpdateService.enableOrDisableInAdmin(paramsJSON.getLong("id"), paramsJSON.getInt("status")); + } + +} \ No newline at end of file diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java similarity index 97% rename from mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java rename to mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java index 1ab77400..1c296697 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AdminAppMarketUpdateController.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java @@ -24,7 +24,7 @@ import javax.annotation.Resource; @Api(tags = "安卓应用市场 APP 版本检查") @RestController @RequestMapping("/mobile/admin/app-market-update") -public class AdminAppMarketUpdateController { +public class AppMarketUpdateController { @Resource private AdminAppMarketUpdateService adminAppMarketUpdateService; diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java index 67394650..62aa04bd 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java @@ -8,7 +8,9 @@ package com.suisung.mall.admin.service; +import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; public interface AdminAppMarketUpdateService { @@ -23,4 +25,49 @@ public interface AdminAppMarketUpdateService { CommonResult checkLatestVersion(Integer marketId, String packageName, Integer currVersionKey); + /** + * 后台管理员搜索列表 + * + * @param marketId + * @param keyword + * @param pageNum + * @param pageSize + * @return + */ + CommonResult searchListInAdmin(Integer marketId, String keyword, Integer pageNum, Integer pageSize); + + /** + * 后台管理员新增 + * + * @param paramsJSON + * @return + */ + CommonResult addNewInAdmin(JSONObject paramsJSON); + + /** + * 后台管理员修改 + * + * @param paramsJSON + * @return + */ + CommonResult modifyInAdmin(JSONObject paramsJSON); + + /** + * 后台管理员禁用/启用 + * + * @param id + * @param status + * @return + */ + CommonResult enableOrDisableInAdmin(Long id, Integer status); + + /** + * 获取一条记录 + * + * @param marketId + * @param packageName + * @param versionKey + * @return + */ + AdminAppMarketUpdate getAppMarketUpdate(Integer marketId, String packageName, Integer versionKey); } diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java index 63772bd2..a7f38e9a 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java @@ -9,14 +9,23 @@ package com.suisung.mall.admin.service.impl; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.admin.mapper.AdminAppMarketUpdateMapper; import com.suisung.mall.admin.service.AdminAppMarketUpdateService; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; +import com.suisung.mall.common.pojo.dto.FileInfoDTO; +import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import org.springframework.stereotype.Service; +import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; + @Service public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl implements AdminAppMarketUpdateService { /** @@ -33,20 +42,181 @@ public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("market_id", marketId).eq("package_name", packageName) - .orderByDesc("version_key").last("limit 1"); - - AdminAppMarketUpdate adminAppMarketUpdate = getOne(queryWrapper); + AdminAppMarketUpdate adminAppMarketUpdate = getAppMarketUpdate(marketId, packageName, currVersionKey); if (adminAppMarketUpdate == null) { - return CommonResult.failed("当前应用已是最新版本"); + return CommonResult.failed("当前已是最新版本"); } - if (!ObjectUtil.isEmpty(currVersionKey) && adminAppMarketUpdate.getVersion_key() <= currVersionKey) { - return CommonResult.failed("当前应用已是最新版本"); + return CommonResult.failed("当前已是最新版本"); + } + + // 更新包后缀处理 + if (StrUtil.isNotBlank(adminAppMarketUpdate.getDownload_url()) && StrUtil.isBlank(adminAppMarketUpdate.getFile_ext())) { + adminAppMarketUpdate.setFile_ext(StringUtils.getFileExt(adminAppMarketUpdate.getDownload_url())); } return CommonResult.success(adminAppMarketUpdate); } + + /** + * 后台管理员搜索列表 + * + * @param marketId + * @param keyword + * @return + */ + @Override + public CommonResult searchListInAdmin(Integer marketId, String keyword, Integer pageNum, Integer pageSize) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (ObjectUtil.isNotEmpty(marketId)) { + queryWrapper.eq("market_id", marketId); + } + if (StrUtil.isNotBlank(keyword)) { + queryWrapper.and(wrapper -> wrapper.like("package_name", keyword) + .or().like("version_name", keyword) + .or().like("description", keyword)); + } + + queryWrapper.orderByDesc("id"); + + Page list = lists(queryWrapper, pageNum, pageSize); + + return CommonResult.success(list); + } + + /** + * 后台管理员新增 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult addNewInAdmin(JSONObject paramsJSON) { + String userId = "0"; + UserDto user = getCurrentUser(); + if (user != null) { + userId = String.valueOf(user.getId()); + } + + if (ObjectUtil.isEmpty(paramsJSON)) { + return CommonResult.failed("缺少必要参数"); + } + + + AdminAppMarketUpdate adminAppMarketUpdate = JSONUtil.toBean(paramsJSON, AdminAppMarketUpdate.class); + if (ObjectUtil.isEmpty(adminAppMarketUpdate)) { + return CommonResult.failed("参数格式有误"); + } + + + if (ObjectUtil.isEmpty(adminAppMarketUpdate.getMarket_id()) || ObjectUtil.isEmpty(adminAppMarketUpdate.getPackage_name()) + || ObjectUtil.isEmpty(adminAppMarketUpdate.getVersion_key()) || ObjectUtil.isEmpty(adminAppMarketUpdate.getVersion_name()) + || ObjectUtil.isEmpty(adminAppMarketUpdate.getDownload_url())) { + return CommonResult.failed("缺少关键参数"); + } + + AdminAppMarketUpdate record = getAppMarketUpdate(adminAppMarketUpdate.getMarket_id(), adminAppMarketUpdate.getPackage_name(), adminAppMarketUpdate.getVersion_key()); + if (record != null) { + return CommonResult.failed("当前版本升级包已存在"); + } + + FileInfoDTO fileInfoDTO = StringUtils.getFileInfoFromUrl(adminAppMarketUpdate.getDownload_url()); + if (fileInfoDTO != null) { + adminAppMarketUpdate.setPackage_size(fileInfoDTO.getFileSize()); + adminAppMarketUpdate.setFile_ext(fileInfoDTO.getFileExtension()); + adminAppMarketUpdate.setMd5_checksum(fileInfoDTO.getMd5()); + } + + adminAppMarketUpdate.setCreated_by(userId); + adminAppMarketUpdate.setUpdated_by(userId); + + return add(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 后台管理员修改 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult modifyInAdmin(JSONObject paramsJSON) { + String userId = "0"; + UserDto user = getCurrentUser(); + if (user != null) { + userId = String.valueOf(user.getId()); + } + + if (ObjectUtil.isEmpty(paramsJSON)) { + return CommonResult.failed("缺少必要参数"); + } + + if (ObjectUtil.isEmpty(paramsJSON.getLong("id"))) { + return CommonResult.failed("缺少id参数"); + } + + AdminAppMarketUpdate adminAppMarketUpdate = JSONUtil.toBean(paramsJSON, AdminAppMarketUpdate.class); + if (ObjectUtil.isEmpty(adminAppMarketUpdate)) { + return CommonResult.failed("参数格式有误"); + } + + FileInfoDTO fileInfoDTO = StringUtils.getFileInfoFromUrl(adminAppMarketUpdate.getDownload_url()); + if (fileInfoDTO != null) { + adminAppMarketUpdate.setPackage_size(fileInfoDTO.getFileSize()); + adminAppMarketUpdate.setFile_ext(fileInfoDTO.getFileExtension()); + adminAppMarketUpdate.setMd5_checksum(fileInfoDTO.getMd5()); + } + + adminAppMarketUpdate.setUpdated_by(userId); + + return saveOrUpdate(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 后台管理员禁用/启用 + * + * @param id + * @param status + * @return + */ + @Override + public CommonResult enableOrDisableInAdmin(Long id, Integer status) { + Integer userId = 0; + UserDto user = getCurrentUser(); + if (user != null) { + userId = user.getId(); + } + + if (ObjectUtil.isEmpty(id) || ObjectUtil.isEmpty(status)) { + return CommonResult.failed("缺少必要参数"); + } + + AdminAppMarketUpdate adminAppMarketUpdate = new AdminAppMarketUpdate(); + adminAppMarketUpdate.setId(id); + adminAppMarketUpdate.setStatus(status); + adminAppMarketUpdate.setUpdated_by(String.valueOf(userId)); + return saveOrUpdate(adminAppMarketUpdate) ? CommonResult.success() : CommonResult.failed("操作失败"); + } + + /** + * 获取一条记录 + * + * @param marketId + * @param packageName + * @param versionKey + * @return + */ + @Override + public AdminAppMarketUpdate getAppMarketUpdate(Integer marketId, String packageName, Integer versionKey) { + if (ObjectUtil.isEmpty(marketId) || ObjectUtil.isEmpty(packageName) || ObjectUtil.isEmpty(versionKey)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("market_id", marketId).eq("package_name", packageName) + .eq("version_key", versionKey); + + return findOne(queryWrapper); + } } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java index 91e9b252..e7c68534 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java @@ -46,6 +46,9 @@ public class AdminAppMarketUpdate implements Serializable { @ApiModelProperty(value = "热更新包的下载链接,用户可通过此链接下载更新包完成应用更新") private String download_url; + @ApiModelProperty(value = "更新包后缀:apk, wgt") + private String file_ext; + @ApiModelProperty(value = "热更新的发布时间,记录更新包正式发布的时刻") private Date release_time; diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java new file mode 100644 index 00000000..f718f776 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/FileInfoDTO.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.pojo.dto; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +@ApiModel(value = "文件信息", description = "文件信息") +public class FileInfoDTO { + + String md5; + String fileExtension; + long fileSize; + + public FileInfoDTO(String md5, String fileExtension, long fileSize) { + this.md5 = md5; + this.fileExtension = fileExtension; + this.fileSize = fileSize; + } + + @Override + public String toString() { + return "MD5: " + md5 + ", 文件后缀: " + fileExtension + ", 文件大小: " + fileSize + " 字节"; + } + +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java index eba58e3e..31fa3e85 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java @@ -1,7 +1,9 @@ package com.suisung.mall.common.utils; +import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.*; +import com.suisung.mall.common.pojo.dto.FileInfoDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -10,8 +12,12 @@ import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLEncoder; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.MessageFormat; import java.text.SimpleDateFormat; @@ -709,6 +715,64 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { return false; } + /** + * 根据url文件,生成文件MD5文摘签名 + * + * @param fileUrl + * @return + */ + public static FileInfoDTO getFileInfoFromUrl(String fileUrl) { + if (StrUtil.isBlank(fileUrl)) { + return null; + } + + try { + URL url = new URL(fileUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + // 获取文件大小 + long fileSize = connection.getContentLengthLong(); + + // 获取文件后缀 + String path = url.getPath(); + String fileExtension = ""; + int dotIndex = path.lastIndexOf('.'); + if (dotIndex != -1) { + fileExtension = path.substring(dotIndex + 1); + } + + try (InputStream inputStream = connection.getInputStream()) { + // 获取 MD5 消息摘要实例 + MessageDigest digest = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[8192]; + int bytesRead; + // 从输入流读取数据并更新摘要 + while ((bytesRead = inputStream.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead); + } + // 完成摘要计算 + byte[] md5Bytes = digest.digest(); + // 将字节数组转换为十六进制字符串 + StringBuilder md5String = new StringBuilder(); + for (byte b : md5Bytes) { + md5String.append(String.format("%02x", b)); + } + String md5 = md5String.toString(); + return new FileInfoDTO(StrUtil.isBlank(md5) ? "" : md5, fileExtension, fileSize); + } finally { + connection.disconnect(); + } + } catch (MalformedURLException e) { + logger.error("错误:提供的 URL 格式不正确,请检查 URL 字符串", e); + } catch (NoSuchAlgorithmException e) { + logger.error("错误:系统不支持 MD5 算法,这可能是 Java 环境的问题", e); + } catch (IOException e) { + logger.error("错误:在连接 URL 或读取文件内容时发生 I/O 异常,可能是网络问题或文件不存在", e); + } + return null; + } + /** * 生成的随机数类型 From 39e52b54fd9d7d50eaad0a3af13cea97b11daf65 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Wed, 23 Apr 2025 22:43:34 +0800 Subject: [PATCH 02/39] =?UTF-8?q?=E7=83=AD=E6=9B=B4=E6=96=B0=E5=8C=85?= =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/AdminAppMarketUpdateService.java | 5 +- .../impl/AdminAppMarketUpdateServiceImpl.java | 75 +++++++++++++++---- .../modules/admin/AdminAppMarketUpdate.java | 7 +- .../lakala/controller/LklTkController.java | 8 +- .../{CommonService.java => LklTkService.java} | 4 +- 5 files changed, 72 insertions(+), 27 deletions(-) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/{CommonService.java => LklTkService.java} (99%) diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java index 62aa04bd..083ac55a 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java @@ -62,12 +62,11 @@ public interface AdminAppMarketUpdateService { CommonResult enableOrDisableInAdmin(Long id, Integer status); /** - * 获取一条记录 + * 获取最后一条记录 * * @param marketId * @param packageName - * @param versionKey * @return */ - AdminAppMarketUpdate getAppMarketUpdate(Integer marketId, String packageName, Integer versionKey); + AdminAppMarketUpdate getLastAppMarketUpdate(Integer marketId, String packageName); } diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java index a7f38e9a..f2a762ad 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java @@ -22,12 +22,16 @@ import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; import com.suisung.mall.common.pojo.dto.FileInfoDTO; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; @Service public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl implements AdminAppMarketUpdateService { + @Value("${spring.profiles.active}") + private String profile; + /** * 获取某个市场的最新 APP 版本 * @@ -42,18 +46,32 @@ public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("market_id", marketId).eq("package_name", packageName) - .eq("version_key", versionKey); + queryWrapper.eq("market_id", marketId) + .eq("package_name", packageName).orderByDesc("version_key"); return findOne(queryWrapper); } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java index e7c68534..6608505e 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/admin/AdminAppMarketUpdate.java @@ -43,8 +43,11 @@ public class AdminAppMarketUpdate implements Serializable { @ApiModelProperty(value = "热更新包显示的版本号,用于标识不同的热更新版本,遵循一定命名规则,如 1.23.21") private String version_name; - @ApiModelProperty(value = "热更新包的下载链接,用户可通过此链接下载更新包完成应用更新") - private String download_url; + @ApiModelProperty(value = "apk包的下载链接,用户可通过此链接下载更新包完成应用更新") + private String download_apk_url; + + @ApiModelProperty(value = "增量包的下载链接,用户可通过此链接下载更新包完成应用更新") + private String download_wgt_url; @ApiModelProperty(value = "更新包后缀:apk, wgt") private String file_ext; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java index a9f7d7fa..cac3f141 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java @@ -9,7 +9,7 @@ package com.suisung.mall.shop.lakala.controller; import com.suisung.mall.common.service.impl.BaseControllerImpl; -import com.suisung.mall.shop.lakala.service.impl.CommonService; +import com.suisung.mall.shop.lakala.service.impl.LklTkService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,18 +24,18 @@ import javax.annotation.Resource; public class LklTkController extends BaseControllerImpl { @Resource - private CommonService commonService; + private LklTkService lklTkService; @ApiOperation(value = "请求获取token(商户进件)", notes = "请求获取token(商户进件)") @RequestMapping(value = "/token", method = RequestMethod.POST) public String getLklTkAuthorization() { - return commonService.getLklTkAuthorization(); + return lklTkService.getLklTkAuthorization(); } @ApiOperation(value = "请求获取token(商户进件)", notes = "请求获取token(商户进件)") @RequestMapping(value = "/token1", method = RequestMethod.POST) public String getLklTkAuthorization1() { - return commonService.getLklTkAuthorization(); + return lklTkService.getLklTkAuthorization(); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/CommonService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java similarity index 99% rename from mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/CommonService.java rename to mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java index 61c3fb8f..ed23b640 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/CommonService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java @@ -36,9 +36,9 @@ import java.util.HashMap; import java.util.Map; @Service -public class CommonService { +public class LklTkService { - private static final Logger log = LoggerFactory.getLogger(CommonService.class); + private static final Logger log = LoggerFactory.getLogger(LklTkService.class); @Value("${lakala.tk.server_url}") private String serverUrl; From c1896f3c39ac8d0c84e4647353626e5e1e47c10c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Thu, 24 Apr 2025 17:38:12 +0800 Subject: [PATCH 03/39] =?UTF-8?q?shop=20=E9=A1=B9=E7=9B=AE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=8B=89=E5=8D=A1=E6=8B=89=E7=9A=84=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mobile/AppMarketUpdateController.java | 11 + .../service/AdminAppMarketUpdateService.java | 8 + .../impl/AdminAppMarketUpdateServiceImpl.java | 27 +- .../src/main/resources/application.yml | 20 +- .../service/impl/LakalaPayServiceImpl.java | 13 +- .../src/main/resources/bootstrap-prod.yml | 4 +- mall-shop/pom.xml | 16 + .../lakala/controller/LakalaController.java | 69 ++ .../lakala/mapper/LklLedgerMemberMapper.java | 18 + .../LklLedgerMerReceiverBindMapper.java | 18 + .../mapper/LklLedgerReceiverMapper.java | 18 + .../shop/lakala/service/LakalaPayService.java | 138 ++++ .../service/LklLedgerMemberService.java | 39 + .../LklLedgerMerReceiverBindService.java | 39 + .../service/LklLedgerReceiverService.java | 23 + .../service/impl/LakalaPayServiceImpl.java | 741 ++++++++++++++++++ .../impl/LklLedgerMemberServiceImpl.java | 87 ++ .../LklLedgerMerReceiverBindServiceImpl.java | 85 ++ .../impl/LklLedgerReceiverServiceImpl.java | 55 ++ .../mall/shop/lakala/utils/LakalaUtil.java | 238 ++++++ .../impl/ShopMessageTemplateServiceImpl.java | 2 +- .../src/main/resources/bootstrap-dev.yml | 21 + .../src/main/resources/bootstrap-local.yml | 21 + .../src/main/resources/bootstrap-prod.yml | 21 + .../src/main/resources/bootstrap-test.yml | 21 + .../src/main/resources/bootstrap-uat.yml | 21 + .../mapper/lakala/LklLedgerMemberMapper.xml | 4 + .../lakala/LklLedgerMerReceiverBindMapper.xml | 4 + .../mapper/lakala/LklLedgerReceiverMapper.xml | 4 + 29 files changed, 1768 insertions(+), 18 deletions(-) create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMemberMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMerReceiverBindMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerReceiverMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklLedgerMemberMapper.xml create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java index 1c296697..0e34da81 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/controller/mobile/AppMarketUpdateController.java @@ -9,6 +9,7 @@ package com.suisung.mall.admin.controller.mobile; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONObject; import com.suisung.mall.admin.service.AdminAppMarketUpdateService; import com.suisung.mall.common.api.CommonResult; @@ -35,4 +36,14 @@ public class AppMarketUpdateController { return adminAppMarketUpdateService.checkLatestVersion(paramsJSON.getInt("marketId"), paramsJSON.getStr("packageName"), paramsJSON.getInt("currVersionKey")); } + @ApiOperation(value = "最新通用商家版App下载地址", notes = "最新通用商家版App下载地址") + @RequestMapping(value = "/last/apk", method = RequestMethod.POST) + public CommonResult lastCommonApp(@RequestBody(required = false) JSONObject paramsJSON) { + Integer marketId = 100; + if (paramsJSON != null && ObjectUtil.isNotEmpty(paramsJSON.getInt("marketId"))) { + marketId = paramsJSON.getInt("marketId"); + } + return adminAppMarketUpdateService.lastAdminAppMarketUpdate(marketId); + } + } diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java index 083ac55a..010c31e9 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/AdminAppMarketUpdateService.java @@ -24,6 +24,14 @@ public interface AdminAppMarketUpdateService { */ CommonResult checkLatestVersion(Integer marketId, String packageName, Integer currVersionKey); + /** + * 获取最新的(默认通用)商家版 App 下载地址 + * + * @param marketId + * @return + */ + CommonResult lastAdminAppMarketUpdate(Integer marketId); + /** * 后台管理员搜索列表 diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java index f2a762ad..5d189e1f 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/service/impl/AdminAppMarketUpdateServiceImpl.java @@ -17,6 +17,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.admin.mapper.AdminAppMarketUpdateMapper; import com.suisung.mall.admin.service.AdminAppMarketUpdateService; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.modules.admin.AdminAppMarketUpdate; import com.suisung.mall.common.pojo.dto.FileInfoDTO; @@ -77,6 +78,30 @@ public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("market_id", marketId).eq("status", CommonConstant.Enable).orderByDesc("version_key"); + + AdminAppMarketUpdate adminAppMarketUpdate = findOne(queryWrapper); + if (adminAppMarketUpdate == null) { + return CommonResult.success(null, "没有找到最新版本"); + } + + return CommonResult.success(adminAppMarketUpdate); + } + /** * 后台管理员搜索列表 * @@ -257,7 +282,7 @@ public class AdminAppMarketUpdateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("market_id", marketId) + queryWrapper.eq("market_id", marketId).eq("status", CommonConstant.Enable) .eq("package_name", packageName).orderByDesc("version_key"); return findOne(queryWrapper); diff --git a/mall-gateway/src/main/resources/application.yml b/mall-gateway/src/main/resources/application.yml index 237ccd9b..f9e85cd1 100644 --- a/mall-gateway/src/main/resources/application.yml +++ b/mall-gateway/src/main/resources/application.yml @@ -69,29 +69,29 @@ secure: - "/admin/account/account-user-base/register" - "/admin/account/account-user-base/login" - "/static/image/**" - - "/mobile/pay/index/notify_url" - #- "/mobile/pay/index/lkl_wxPay_notify_url" #拉卡拉微信支付回调 - - "/mobile/pay/index/return_url" - "/shop/static/**" - - "/mobile/shop/qrcode/getQrcode" - - "/admin/shop/shop-base-config/image" + - "/admin/account/open/**" - "/admin/account/account-user-base/doLogin" + #- "/mobile/pay/index/lkl_wxPay_notify_url" #拉卡拉微信支付回调 + - "/mobile/pay/index/notify_url" + - "/mobile/pay/index/return_url" - "/admin/pay/pay-user-resource/userInfoImport" - "/admin/pay/pay-card-history/payCardHistoryImport" + - "/admin/pay/payController/wxRefundNotify" + - "/mobile/shop/qrcode/getQrcode" - "/admin/shop/shop-purchase-invoice/impPurchaseInvoiceTemp" - "/admin/shop/shop-product-base/impProductTemp" - - "/admin/pay/payController/wxRefundNotify" + - "/admin/shop/shop-base-config/image" + - "/mobile/shop/sf-express/order/status/listening/**" + - "/admin/shop/open/**" + - "/admin/shop/esign/async/notify" #E签宝电子签章异步回调 - "/shop/sf-express/cancel-order/notify" - "/shop/sf-express/rider-order-status/notify" - "/shop/sf-express/order-complete/notify" - "/shop/sync/third/**" - - "/mobile/shop/sf-express/order/status/listening/**" - - "/admin/shop/open/**" - - "/admin/account/open/**" - "/esProduct/**" - "/admin/oss/upload/**" - "/mobile/**/**/test/case" - - "/admin/shop/esign/async/notify" #E签宝电子签章异步回调 universal: urls: - "/admin/account/account-user-base/info" diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index 7c7c0e2b..e964a00d 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -103,6 +103,10 @@ public class LakalaPayServiceImpl implements LakalaPayService { return true; } + protected boolean isProd() { + return "prod".equalsIgnoreCase(profile); + } + @Override public cn.hutool.json.JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId) { // 1. 配置初始化 @@ -419,19 +423,19 @@ public class LakalaPayServiceImpl implements LakalaPayService { String fileName = paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); - // 文件上传到拉卡拉服务器 + // 分账结算委托书文件上传到拉卡拉服务器 JSONObject fileUploadResp = uploadFile(orderNo, "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), paramsJSON.getStr("splitEntrustFile")); if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); } String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); - req.setSplitEntrustFilePath(splitEntrustFilePath); -// req.setSplitEntrustFilePath("G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf"); + req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; - if (profile.equals("prod")) { + if (isProd()) { projectDomain = projectDomain + "/api"; } + // 给拉卡拉通知的回调地址 String retUrl = projectDomain + "/mobile/pay/lakala/ledger/applyLedgerMerNotify"; req.setRetUrl(retUrl); @@ -503,6 +507,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { reqData.getStr("auditStatus"), reqData.getStr("auditStatusText"), reqData.getStr("remark")); + if (success) { respData.put("retCode", "000000"); respData.put("retMsg", "操作成功!"); diff --git a/mall-pay/src/main/resources/bootstrap-prod.yml b/mall-pay/src/main/resources/bootstrap-prod.yml index ec36094c..e0f6e1fb 100644 --- a/mall-pay/src/main/resources/bootstrap-prod.yml +++ b/mall-pay/src/main/resources/bootstrap-prod.yml @@ -115,7 +115,7 @@ project: domain: @project.domain@ #拉卡拉支付和分账 lakala: - # 服务地址 + #服务地址 server_url: https://s2.lakala.com #应用Id app_id: OP10000439 @@ -127,7 +127,7 @@ lakala: api_pri_key_path: payKey/lakala/prod/api_private_key.pem #拉卡拉平台证书 lkl_platform_cer_path: payKey/lakala/prod/lkl_platform.cer - # 机构代码 + #机构代码 org_code: 980688 #商户号 merchant_no: 8226330599900LN diff --git a/mall-shop/pom.xml b/mall-shop/pom.xml index a7cb0458..9059009a 100644 --- a/mall-shop/pom.xml +++ b/mall-shop/pom.xml @@ -278,6 +278,22 @@ 9.4.1.jre8 + + + com.lkl.laop.sdk + lkl-laop-java-sdk + 1.0.7 + ${project.basedir}/src/main/resources/lib/lkl-java-sdk-1.0.7.jar + system + + + com.github.javen205 + IJPay-Core + 2.8.0 + compile + + + diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java new file mode 100644 index 00000000..25a965d3 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.controller; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.lakala.service.LakalaPayService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.util.Base64Utils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Api(tags = "拉卡拉相关接口 - 前端控制器") +@RestController +@RequestMapping("/mobile/shop/lakala") +public class LakalaController extends BaseControllerImpl { + + @Resource + private LakalaPayService lakalaPayService; + + @ApiOperation(value = "本地文件转base64", notes = "本地文件转base64") + @RequestMapping(value = "/file2base64", method = RequestMethod.POST) + public String file2Base64(@RequestParam("file") MultipartFile file) throws IOException { + String str = Base64Utils.encodeToString(file.getBytes()); + return str; + } + + @ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请") + @RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST) + public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) { + return lakalaPayService.applyLedgerMer(paramsJSON); + } + + @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调") + @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) + public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) { + return lakalaPayService.applyLedgerMerNotify(request); + } + + @ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请") + @RequestMapping(value = "/ledger/applyLedgerReceiver", method = RequestMethod.POST) + public CommonResult applyLedgerReceiver(@RequestBody JSONObject paramsJSON) { + return lakalaPayService.applyLedgerReceiver(paramsJSON); + } + + @ApiOperation(value = "分账关系绑定申请", notes = "分账关系绑定申请") + @RequestMapping(value = "/ledger/applyBind", method = RequestMethod.POST) + public CommonResult applyBind(@RequestBody JSONObject paramsJSON) { + return lakalaPayService.applyLedgerMerReceiverBind(paramsJSON); + } + + @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") + @RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST) + public JSONObject applyBindNotify(HttpServletRequest request) { + return lakalaPayService.applyLedgerMerReceiverBindNotify(request); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMemberMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMemberMapper.java new file mode 100644 index 00000000..0771b25b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMemberMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklLedgerMember; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklLedgerMemberMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMerReceiverBindMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMerReceiverBindMapper.java new file mode 100644 index 00000000..0129a889 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerMerReceiverBindMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklLedgerMerReceiverBindMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerReceiverMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerReceiverMapper.java new file mode 100644 index 00000000..90703b25 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerReceiverMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklLedgerReceiverMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java new file mode 100644 index 00000000..2166834e --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public interface LakalaPayService { + + Boolean initLKLSDK(); + + JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId); + + /** + * 拉卡拉预下单 + * 参考:https://o.lakala.com/#/home/document/detail?id=110 + * + * @param merchantNo 商户号 + * @param termNo 终端号 + * @param xcxAppId 小程序appid + * @param openId openid + * @param orderId 订单号 + * @param subject 订单标题 + * @param totalAmount 订单金额 + * @param notifyURL 回调地址 + * @param requestIP 请求ip + * @param remark 备注 + * @return + */ + JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark); + + /** + * 聚合扫码-交易查询 + * + * @param storeId + * @param orderId + * @return + */ + JSONObject tradeQuery(Integer storeId, String orderId); + + /** + * 聚合扫码-退款交易 + * 主被扫交易发生后,因商家或消费者原因需要退款时,商家调用此接口退还消费者支付款项。 + * 注意: 1、调用退款接口时请保证商户/账户余额大于等于本次退款金额 + * + * @param storeId + * @param out_trade_no + * @param origin_trade_no // 原拉卡拉交易流水号 + * @param refund_amount 单位分,整数数字型字符 + * @param refund_reason + * @param requestIP + * @return + */ + JSONObject refund(Integer storeId, String out_trade_no, String origin_trade_no, String refund_amount, String refund_reason, String requestIP); + + /** + * 账户余额查询 + * 参考:https://o.lakala.com/#/home/document/detail?id=364 + * + * @param orgNo bmcp机构号 + * @param merchantNo 商户号 或 receiveNo 或 商户用户编号 + * @param payNo 账号(若该参数上送,则payType将无效) + * @param payType 账号类型(01:收款账户,02:付款账户,03:分账商户账户,04:分账接收方账户,05:充值代付账户,06:结算代付账户)- 未上送则默认为01 + * @return + */ + JSONObject ewalletBalanceQuery(String orgNo, String merchantNo, String payNo, String payType); + + /** + * 文件上传 + * 参考:https://o.lakala.com/#/home/document/detail?id=90 + * + * @param orderNo + * @param attType + * @param attExtName + * @param attContext + * @return + */ + JSONObject uploadFile(String orderNo, String attType, String attExtName, String attContext); + + + /** + * 商户分账业务开通申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param paramsJSON + * @return + */ + CommonResult applyLedgerMer(JSONObject paramsJSON); + + /** + * 商户分账业务开通申请回调 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param request + * @return + */ + JSONObject applyLedgerMerNotify(HttpServletRequest request); + + /** + * 分账接收方创建申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=380 + * + * @param paramsJSON + * @return + */ + CommonResult applyLedgerReceiver(JSONObject paramsJSON); + + + /** + * 分账关系绑定申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=386 + * + * @param paramsJSON + * @return + */ + CommonResult applyLedgerMerReceiverBind(JSONObject paramsJSON); + + + /** + * 分账关系绑定申请回调 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param request + * @return + */ + JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request); + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java new file mode 100644 index 00000000..4c11850f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import com.suisung.mall.common.modules.lakala.LklLedgerMember; +import com.suisung.mall.core.web.service.IBaseService; + +public interface LklLedgerMemberService extends IBaseService { + + /** + * 根据银联商户号新增或修改记录 + * + * @param record + * @return + */ + Boolean saveOrUpdateByMerCupNo(LklLedgerMember record); + + + /** + * 更新审核结果 + * + * @param applyId + * @param merInnerNo + * @param merCupNo + * @param entrustFileName + * @param entrustFilePath + * @param auditStatus + * @param auditStatusText + * @param remark + * @return + */ + Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java new file mode 100644 index 00000000..002e4e03 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; +import com.suisung.mall.core.web.service.IBaseService; + +public interface LklLedgerMerReceiverBindService extends IBaseService { + + /** + * 根据接收方编号新增或更新记录 + * + * @param record + * @return + */ + Boolean saveOrUpdateByMerCupNoReceiverNo(LklLedgerMerReceiverBind record); + + /** + * 更新审核结果 + * + * @param applyId + * @param merInnerNo + * @param merCupNo + * @param receiverNo + * @param entrustFileName + * @param entrustFilePath + * @param auditStatus + * @param auditStatusText + * @param remark + * @return + */ + Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String receiverNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java new file mode 100644 index 00000000..1baa0a7f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; +import com.suisung.mall.core.web.service.IBaseService; + +public interface LklLedgerReceiverService extends IBaseService { + + /** + * 根据接收方编号新增或更新记录 + * + * @param record + * @return + */ + Boolean saveOrUpdateByReceiverNo(LklLedgerReceiver record); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java new file mode 100644 index 00000000..c57da239 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.ijpay.core.kit.IpKit; +import com.lkl.laop.sdk.LKLSDK; +import com.lkl.laop.sdk.exception.SDKException; +import com.lkl.laop.sdk.request.*; +import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo; +import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.exception.ApiException; +import com.suisung.mall.common.feignService.ShopService; +import com.suisung.mall.common.modules.lakala.LklLedgerMember; +import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; +import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; +import com.suisung.mall.common.modules.store.ShopStoreBase; +import com.suisung.mall.common.utils.I18nUtil; +import com.suisung.mall.common.utils.StringUtils; +import com.suisung.mall.shop.lakala.service.LakalaPayService; +import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; +import com.suisung.mall.shop.lakala.service.LklLedgerMerReceiverBindService; +import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; +import com.suisung.mall.shop.lakala.utils.LakalaUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + + +@Slf4j +@Service +public class LakalaPayServiceImpl implements LakalaPayService { + private static final boolean init = false; + private static final String lklSuccessCode = "000000"; + //### 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 + @Value("${lakala.merchant_no}") + public String merchantNo; // 拉卡拉分配的商户号 + @Value("${lakala.term_no}") + public String termNo; // 拉卡拉分配的终端号码 + @Value("${lakala.server_url}") + private String serverUrl; //服务地址 + @Value("${lakala.app_id}") + private String appId; // 拉卡拉appId + @Value("${lakala.serial_no}") + private String serialNo; // 你的证书序列号 + @Value("${lakala.api_pri_key_path}") + private String priKeyPath; //商户私钥信息地址 + @Value("${lakala.lkl_platform_cer_path}") + private String lklCerPath; //拉卡拉支付平台证书地址 + @Value("${lakala.api_cert_path}") + private String apiCertPath; + @Value("${lakala.lkl_platform_cer_path}") + private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签) + @Value("${lakala.org_code}") + private String orgCode; + @Value("${project.domain}") + private String projectDomain; + @Value("${spring.profiles.active}") + private String profile; + @Lazy + @Autowired + private ShopService shopService; + + @Autowired + private LklLedgerMemberService lklLedgerMemberService; + + @Autowired + private LklLedgerReceiverService lklLedgerReceiverService; + + @Autowired + private LklLedgerMerReceiverBindService lklLedgerMerReceiverBindService; + + /** + * 初始化 拉卡拉SDK + * + * @return + */ + @Override + public Boolean initLKLSDK() { + if (!init) { + return LakalaUtil.initLKLSDK(appId, serialNo, priKeyPath, lklCerPath, lklNotifyCerPath, serverUrl); + } + return true; + } + + protected boolean isProd() { + return "prod".equalsIgnoreCase(profile); + } + + @Override + public JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId) { + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + /*** 微信主扫场景示例 */ + V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest(); + v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo); + v3LabsTransPreorderWechatReq.setTermNo(termNo); + v3LabsTransPreorderWechatReq.setOutTradeNo(orderId); + v3LabsTransPreorderWechatReq.setSubject("油麦菜5斤装特惠"); + v3LabsTransPreorderWechatReq.setAccountType("WECHAT"); + v3LabsTransPreorderWechatReq.setTransType("51"); + v3LabsTransPreorderWechatReq.setTotalAmount("1"); + v3LabsTransPreorderWechatReq.setNotifyUrl("http://mall.gpxscs.cn/notify"); + v3LabsTransPreorderWechatReq.setRemark("测试预下单备注"); + + //地址位置信息 + V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo1 = new V3LabsTradeLocationInfo(IpKit.getRealIp(request)); + v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo1); + + //微信主扫场景下acc_busi_fields域内容 + V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus(); + wechatBus.setSubAppid("wx5a73f844dac0da5c"); // 小程序appId + wechatBus.setUserId("oDVKR7T0qxg6O8tqIL9SgY6LXqqQ"); // 微信 openId + wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB” + v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq); + + //4. 响应 + return JSONUtil.parseObj(responseStr); + } catch (SDKException e) { + LakalaPayServiceImpl.log.error("transPreOrder error", e); + throw new ApiException(I18nUtil._("获取公众号绑定信息失败!"), e); + } + + } + + /** + * 拉卡拉预下单 + * 参考:https://o.lakala.com/#/home/document/detail?id=110 + * + * @param merchantNo 商户号 + * @param termNo 终端号 + * @param xcxAppId 小程序appid + * @param openId openid + * @param orderId 订单号 + * @param subject 订单标题 + * @param totalAmount 订单金额 + * @param notifyURL 回调地址 + * @param requestIP 请求ip + * @param remark 备注 + * @return + */ + @Override + public JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) { + // 1. 配置初始化 + initLKLSDK(); + + if (StrUtil.isBlank(merchantNo)) { + merchantNo = this.merchantNo; + } + if (StrUtil.isBlank(termNo)) { + termNo = this.termNo; + } + + //2. 装配数据 + /*** 微信主扫场景示例 */ + V3LabsTransPreorderRequest v3LabsTransPreorderWechatReq = new V3LabsTransPreorderRequest(); + v3LabsTransPreorderWechatReq.setMerchantNo(merchantNo); + v3LabsTransPreorderWechatReq.setTermNo(termNo); + v3LabsTransPreorderWechatReq.setOutTradeNo(orderId); + v3LabsTransPreorderWechatReq.setSubject(subject); + //微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD + v3LabsTransPreorderWechatReq.setAccountType("WECHAT"); + // 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付) + v3LabsTransPreorderWechatReq.setTransType("51"); + v3LabsTransPreorderWechatReq.setTotalAmount(totalAmount); + v3LabsTransPreorderWechatReq.setSettleType("1"); //“0”或者空,常规结算方式,如需接拉卡拉分账通需传“1”,商户未开通分账之前切记不用上送此参数。; + v3LabsTransPreorderWechatReq.setNotifyUrl(notifyURL); + v3LabsTransPreorderWechatReq.setRemark(remark); + + //地址位置信息 + V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo = new V3LabsTradeLocationInfo(requestIP); + v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo); + + //微信主扫场景下 acc_busi_fields 域内容 + V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus(); + wechatBus.setSubAppid(xcxAppId); // 小程序appId + wechatBus.setUserId(openId); // 微信 openId + wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB” + v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus); + + try { + log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq)); + + //3. 发送请求 + String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq); + log.info("拉卡拉预下单响应数据:{}", responseStr); + if (StrUtil.isBlank(responseStr)) { + return null; + } + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + + // || !lakalaRespJSON.getStr("code").equals("BBS00000") + + //4. 响应 + return lakalaRespJSON; + } catch (SDKException e) { + log.error("拉卡拉支付出错:", e); + throw new ApiException(I18nUtil._("支付失败!"), e); + } + } + + /** + * 聚合扫码-交易查询 + * + * @param storeId + * @param orderId + * @return + */ + @Override + public JSONObject tradeQuery(Integer storeId, String orderId) { + if (ObjectUtil.isEmpty(storeId) || StrUtil.isBlank(orderId)) { + return null; + } + + // 1. 配置初始化 + initLKLSDK(); + + // 这里获取店铺的拉卡拉的商户号和终端号码 + ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); + if (shopStoreBase == null || StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) { + log.error("缺少参数,拉卡拉交易查询失败!"); + return null; + } + + //2. 装配数据 + V3LabsQueryTradequeryRequest v3LabsQueryTradequeryRequest = new V3LabsQueryTradequeryRequest(); + v3LabsQueryTradequeryRequest.setMerchantNo(shopStoreBase.getLkl_merchant_no()); + v3LabsQueryTradequeryRequest.setTermNo(shopStoreBase.getLkl_term_no()); + v3LabsQueryTradequeryRequest.setOutTradeNo(orderId); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(v3LabsQueryTradequeryRequest); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + // || !lakalaRespJSON.getStr("code").equals("BBS00000") + + return lakalaRespJSON; + } catch (SDKException e) { + log.error("交易查询失败:", e); + throw new ApiException(I18nUtil._("交易查询失败!"), e); + } + } + + /** + * 聚合扫码-退款交易 + * 主被扫交易发生后,因商家或消费者原因需要退款时,商家调用此接口退还消费者支付款项。 + * 注意: 1、调用退款接口时请保证商户/账户余额大于等于本次退款金额 + * + * @param storeId + * @param out_trade_no + * @param origin_trade_no // 原拉卡拉交易流水号 + * @param refund_amount 单位分,整数数字型字符 + * @param refund_reason + * @param requestIP + * @return + */ + @Override + public JSONObject refund(Integer storeId, String out_trade_no, String origin_trade_no, String refund_amount, String refund_reason, String requestIP) { + if (ObjectUtil.isEmpty(storeId) || StrUtil.isBlank(out_trade_no) || StrUtil.isBlank(refund_amount) || StrUtil.isBlank(origin_trade_no) || StrUtil.isBlank(requestIP)) { + return null; + } + + // 1. 配置初始化 + initLKLSDK(); + + + // 这里获取店铺的拉卡拉的商户号和终端号码 + ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); + if (shopStoreBase == null || StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) { + log.error("缺少参数,退款交易失败!"); + return null; + } + + //2. 装配数据 + V3LabsRelationIdmrefundRequest req = new V3LabsRelationIdmrefundRequest(); + req.setOutRefundOrderNo(out_trade_no); + req.setMerchantNo(shopStoreBase.getLkl_merchant_no()); + req.setTermNo(shopStoreBase.getLkl_term_no()); + req.setRefundAmount(refund_amount); + req.setRefundReason(refund_reason); + req.setOriginTradeNo(origin_trade_no); + + V3LabsTradeLocationInfo v3LabsTradeLocationInfo = new V3LabsTradeLocationInfo(requestIP, null, ""); + req.setLocationInfo(v3LabsTradeLocationInfo); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + + return lakalaRespJSON; + } catch (SDKException e) { + log.error("退款交易失败:", e); + throw new ApiException(I18nUtil._("退款交易!"), e); + } + } + + /** + * 账户余额查询 + * 参考:https://o.lakala.com/#/home/document/detail?id=364 + * + * @param orgNo bmcp机构号 测试 “1” + * @param merchantNo 商户号 或 receiveNo 或 商户用户编号 + * @param payNo 账号(若该参数上送,则payType将无效) + * @param payType 账号类型(01:收款账户,02:付款账户,03:分账商户账户,04:分账接收方账户,05:充值代付账户,06:结算代付账户)- 未上送则默认为01 + * @return + */ + @Override + public JSONObject ewalletBalanceQuery(String orgNo, String merchantNo, String payNo, String payType) { + if (StrUtil.isBlank(orgNo) || StrUtil.isBlank(merchantNo) || (StrUtil.isBlank(payNo) && StrUtil.isBlank(payType))) { + return null; + } + + // 1. 配置初始化 + initLKLSDK(); + + + //2. 装配数据 + V2LaepIndustryEwalletBalanceQueryRequest req = new V2LaepIndustryEwalletBalanceQueryRequest(); + req.setOrgNo(orgNo); + req.setMerchantNo(merchantNo); + req.setPayNo(payNo); + req.setPayType(payType); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + + return lakalaRespJSON; + } catch (SDKException e) { + log.error("账户余额查询失败:", e); + throw new ApiException(I18nUtil._("账户余额查询!"), e); + } + + } + + /** + * 文件上传 + * 参考:https://o.lakala.com/#/home/document/detail?id=90 + * + * @param orderNo + * @param attType + * @param attExtName + * @param attContext + * @return + */ + @Override + public JSONObject uploadFile(String orderNo, String attType, String attExtName, String attContext) { + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiUploadFileRequest req = new V2MmsOpenApiUploadFileRequest(); + req.setVersion("2.0"); + req.setOrgCode(orgCode); + req.setOrderNo(orderNo); + req.setAttType(attType); + req.setAttExtName(attExtName); + req.setAttContext(attContext); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + } + + return (JSONObject) lakalaRespJSON.get("respData"); + } catch (SDKException e) { + log.error("文件上传失败:", e); + throw new ApiException(I18nUtil._("文件上传失败!"), e); + } + } + + @Override + public CommonResult applyLedgerMer(JSONObject paramsJSON) { + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); + req.setVersion("2.0"); + req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 + req.setOrgCode(orgCode); + req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); + req.setMerCupNo(paramsJSON.getStr("merCupNo")); + req.setContactMobile(paramsJSON.getStr("contactMobile")); + req.setSplitLowestRatio(new BigDecimal(paramsJSON.getStr("splitLowestRatio"))); + String fileName = paramsJSON.getStr("splitEntrustFileName"); + req.setSplitEntrustFileName(fileName); + + // 分账结算委托书文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), paramsJSON.getStr("splitEntrustFile")); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); + } + + String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); + req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + + if (isProd()) { + projectDomain = projectDomain + "/api"; + } + // 给拉卡拉通知的回调地址 + String retUrl = projectDomain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; + req.setRetUrl(retUrl); + + paramsJSON.set("orderNo", req.getOrderNo()); + paramsJSON.set("version", "2.0"); + paramsJSON.set("ret_url", retUrl); + paramsJSON.set("org_code", orgCode); + paramsJSON.set("split_entrust_file_path", splitEntrustFilePath); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); +// responseStr="{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}}"; +// lakalaRespJSON = JSONUtil.parseObj(responseStr); + } + + paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); + paramsJSON.set("audit_status_text", paramsJSON.get("remark")); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); + lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMember); + + return CommonResult.success(null, "提交成功,待审核中!"); + } catch (SDKException e) { + log.error("分账申请失败:", e); + throw new ApiException(I18nUtil._("申请失败!"), e); + } + } + + /** + * 商户分账业务开通申请回调 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param request + * @return + */ + @Override + public JSONObject applyLedgerMerNotify(HttpServletRequest request) { + log.info("商户分账申请业务回调收到通知"); + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + log.info("商户分账申请业务回调返回参数:{}", requestBody); + + boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); + if (!checkSuccess) { + log.info("商户分账申请业务回调:验签失败"); + return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + } + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); + + JSONObject respData = new JSONObject(); + respData.put("retCode", "OP90003"); + respData.put("retMsg", "响应处理失败!"); + + if (paramsJSON != null) { + JSONObject reqData = (JSONObject) paramsJSON.get("respData"); + if (ObjectUtil.isEmpty(reqData)) { + return respData; + } + + // 更改本地分账记录状态数据 + Boolean success = lklLedgerMemberService.updateAuditResult(reqData.getStr("applyId"), + reqData.getStr("merInnerNo"), + reqData.getStr("merCupNo"), + reqData.getStr("entrustFileName"), + reqData.getStr("entrustFilePath"), + reqData.getStr("auditStatus"), + reqData.getStr("auditStatusText"), + reqData.getStr("remark")); + + if (success) { + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.info("商户分账申请业务回调:处理成功"); + } + } + + return respData; + } + + /** + * 分账接收方创建申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=380 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult applyLedgerReceiver(JSONObject paramsJSON) { + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyLedgerReceiverRequest req = new V2MmsOpenApiLedgerApplyLedgerReceiverRequest(); + + String orderNo = StringUtils.genLklOrderNo(8); // 8位随机数 + req.setOrderNo(orderNo); + req.setOrgCode(orgCode); + req.setVersion("2.0"); + + req.setReceiverName(paramsJSON.getStr("receiverName")); + req.setContactMobile(paramsJSON.getStr("contactMobile")); + + req.setLicenseNo(paramsJSON.getStr("licenseNo")); + req.setLicenseName(paramsJSON.getStr("licenseName")); + req.setLegalPersonName(paramsJSON.getStr("legalPersonName")); + req.setLegalPersonCertificateType(paramsJSON.getStr("legalPersonCertificateType")); + req.setLegalPersonCertificateNo(paramsJSON.getStr("legalPersonCertificateNo")); + + req.setAcctNo(paramsJSON.getStr("acctNo")); + req.setAcctName(paramsJSON.getStr("acctName")); + req.setAcctTypeCode(paramsJSON.getStr("acctTypeCode")); + req.setAcctCertificateType(paramsJSON.getStr("acctCertificateType")); + + req.setAcctCertificateNo(paramsJSON.getStr("acctCertificateNo")); + req.setAcctOpenBankCode(paramsJSON.getStr("acctOpenBankCode")); + req.setAcctOpenBankName(paramsJSON.getStr("acctOpenBankName")); + req.setAcctClearBankCode(paramsJSON.getStr("acctClearBankCode")); + + if (paramsJSON.getJSONArray("attachList") != null && paramsJSON.getJSONArray("attachList").size() > 0) { + List attachList = new ArrayList<>(); + V2MmsOpenApiLedgerApplyLedgerReceiverRequest.AttachInfo attachInfo = new V2MmsOpenApiLedgerApplyLedgerReceiverRequest.AttachInfo(); + for (JSONObject attachJSON : paramsJSON.getJSONArray("attachList").jsonIter()) { + String fileName = attachJSON.getStr("attachName"); + String attachType = attachJSON.getStr("attachType"); + String fileBase64 = attachJSON.getStr("attachStoreFile"); + attachInfo.setAttachName(fileName); + attachInfo.setAttachType(attachType); + + JSONObject fileUploadResp = uploadFile(StringUtils.genLklOrderNo(8), attachType, + StringUtils.getFileExt(fileName), fileBase64); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + throw new ApiException(I18nUtil._("附件上传失败!")); + } + + attachInfo.setAttachStorePath(fileUploadResp.getStr("attFileId")); + attachList.add(attachInfo); + } + + req.setAttachList(attachList); + paramsJSON.set("attach_list", JSONUtil.toJsonStr(attachList)); + } + + paramsJSON.set("orderNo", orderNo); + paramsJSON.set("version", "2.0"); + paramsJSON.set("org_code", orgCode); + + try { + //3. 发送请求,申请创建分账接收方 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + } + + paramsJSON.set("receiver_no", lakalaRespJSON.getByPath("respData.receiverNo")); + paramsJSON.set("org_id", lakalaRespJSON.getByPath("respData.orgId")); + paramsJSON.set("org_name", lakalaRespJSON.getByPath("respData.orgName")); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerReceiver lklLedgerReceiver = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerReceiver.class); + + // 新增或修改本地数据 + lklLedgerReceiverService.saveOrUpdateByReceiverNo(lklLedgerReceiver); + + return CommonResult.success(null, "接收方创建成功!"); + } catch (SDKException e) { + log.error("接收方创建失败:", e); + throw new ApiException(I18nUtil._("接收方创建失败!"), e); + } + } + + /** + * 分账关系绑定申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=386 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult applyLedgerMerReceiverBind(JSONObject paramsJSON) { + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyBindRequest req = new V2MmsOpenApiLedgerApplyBindRequest(); + + String orderNo = StringUtils.genLklOrderNo(8); // 8位随机数 + req.setOrderNo(orderNo); + req.setOrgCode(orgCode); + req.setVersion("2.0"); + + req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); + req.setMerCupNo(paramsJSON.getStr("merCupNo")); + req.setReceiverNo(paramsJSON.getStr("receiverNo")); + + String fileName = paramsJSON.getStr("entrustFileName"); + String splitEntrustFileBase64 = paramsJSON.getStr("entrustFile"); + req.setEntrustFileName(fileName); + + String retUrl = projectDomain + "/mobile/pay/lakala/ledger/applyLedgerMerReceiverBindNotify"; + req.setRetUrl(retUrl); + + // 文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(orderNo, + "SPLIT_COOPERATION_FILE", + StringUtils.getFileExt(fileName), + splitEntrustFileBase64); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + throw new ApiException(I18nUtil._("合作协议上传失败!")); + } + + String entrustFilePath = fileUploadResp.getStr("attFileId"); + req.setEntrustFilePath(entrustFilePath); + + paramsJSON.set("orderNo", orderNo); + paramsJSON.set("version", "2.0"); + paramsJSON.set("ret_url", retUrl); + paramsJSON.set("org_code", orgCode); + paramsJSON.set("entrust_file_name", fileName); + paramsJSON.set("entrust_file_path", entrustFilePath); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + } + + paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerMerReceiverBind lklLedgerMerReceiverBind = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMerReceiverBind.class); + lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(lklLedgerMerReceiverBind); + + return CommonResult.success(null, "提交成功,待审核中!"); + } catch (SDKException e) { + log.error("分账绑定关系申请失败:", e); + throw new ApiException(I18nUtil._("分账绑定关系申请失败!"), e); + } + } + + /** + * 分账关系绑定申请回调 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param request + * @return + */ + @Override + public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + + boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); + if (!checkSuccess) { + return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + } + +// String requestBody = LakalaUtil.getBody(request); + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); + JSONObject respData = new JSONObject(); + respData.put("retCode", "OP90003"); + respData.put("retMsg", "响应处理失败!"); + + if (paramsJSON != null && paramsJSON.get("respData") != null) { + JSONObject reqData = (JSONObject) paramsJSON.get("respData"); + + Boolean success = lklLedgerMerReceiverBindService.updateAuditResult(reqData.getStr("applyId"), + reqData.getStr("merInnerNo"), + reqData.getStr("merCupNo"), + reqData.getStr("receiverNo"), + reqData.getStr("entrustFileName"), + reqData.getStr("entrustFilePath"), + reqData.getStr("auditStatus"), + reqData.getStr("auditStatusText"), + reqData.getStr("remark")); + if (success) { + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + } + } + + return respData; + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java new file mode 100644 index 00000000..8a7b7b3b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.suisung.mall.common.modules.lakala.LklLedgerMember; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.lakala.mapper.LklLedgerMemberMapper; +import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +public class LklLedgerMemberServiceImpl extends BaseServiceImpl implements LklLedgerMemberService { + + + /** + * 根据银联商户号新增或修改记录 + * + * @param record + * @return + */ + @Override + public Boolean saveOrUpdateByMerCupNo(LklLedgerMember record) { + if (record == null || StrUtil.isBlank(record.getMer_cup_no())) { + return false; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", record.getMer_cup_no()); + List existsRecordList = list(queryWrapper); + if (!CollectionUtil.isEmpty(existsRecordList) + && existsRecordList.get(0) != null + && existsRecordList.get(0).getId() > 0) { + // update + record.setId(existsRecordList.get(0).getId()); + return updateById(record); + } + + return add(record); + } + + /** + * 更新审核结果 + * + * @param applyId + * @param merInnerNo + * @param merCupNo + * @param entrustFileName + * @param entrustFilePath + * @param auditStatus + * @param auditStatusText + * @param remark + * @return + */ + @Override + public Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark) { + if (StrUtil.isBlank(applyId) || StrUtil.isBlank(merCupNo) || StrUtil.isBlank(auditStatus)) { + log.error("缺少参数:applyId={}, merCupNo={}, auditStatus={}", applyId, merCupNo, auditStatus); + return false; + } + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("apply_id", applyId); + updateWrapper.set("mer_inner_no", merInnerNo); + updateWrapper.set("mer_cup_no", merCupNo); + updateWrapper.set("split_entrust_file_name", entrustFileName); + updateWrapper.set("split_entrust_file_path", entrustFilePath); + updateWrapper.set("audit_status", auditStatus); + updateWrapper.set("audit_status_text", auditStatusText); + updateWrapper.set("remark", remark); + + return update(updateWrapper); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java new file mode 100644 index 00000000..f9613a26 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.lakala.mapper.LklLedgerMerReceiverBindMapper; +import com.suisung.mall.shop.lakala.service.LklLedgerMerReceiverBindService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl implements LklLedgerMerReceiverBindService { + /** + * 根据接收方编号新增或更新记录 + * + * @param record + * @return + */ + @Override + public Boolean saveOrUpdateByMerCupNoReceiverNo(LklLedgerMerReceiverBind record) { + if (record == null || StrUtil.isBlank(record.getReceiver_no())) { + return false; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", record.getMer_cup_no()); + queryWrapper.eq("receiver_no", record.getReceiver_no()); + List existsRecordList = list(queryWrapper); + if (!CollectionUtil.isEmpty(existsRecordList) + && existsRecordList.get(0) != null + && existsRecordList.get(0).getId() > 0) { + // update + record.setId(existsRecordList.get(0).getId()); + return updateById(record); + } + + return save(record); + } + + /** + * 更新审核结果 + * + * @param applyId + * @param merInnerNo + * @param merCupNo + * @param receiverNo + * @param entrustFileName + * @param entrustFilePath + * @param auditStatus + * @param auditStatusText + * @param remark + * @return + */ + @Override + public Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String receiverNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark) { + if (StrUtil.isBlank(applyId) || StrUtil.isBlank(merCupNo) || StrUtil.isBlank(receiverNo) || StrUtil.isBlank(auditStatus)) { + return false; + } + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("apply_id", applyId); + updateWrapper.set("receiver_no", receiverNo); + updateWrapper.set("mer_inner_no", merInnerNo); + updateWrapper.set("mer_cup_no", merCupNo); + updateWrapper.set("split_entrust_file_name", entrustFileName); + updateWrapper.set("split_entrust_file_path", entrustFilePath); + updateWrapper.set("audit_status", auditStatus); + updateWrapper.set("audit_status_text", auditStatusText); + updateWrapper.set("remark", remark); + + return update(updateWrapper); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java new file mode 100644 index 00000000..80b3d4d3 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.lakala.mapper.LklLedgerReceiverMapper; +import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class LklLedgerReceiverServiceImpl extends BaseServiceImpl implements LklLedgerReceiverService { + /** + * 根据接收方编号新增或更新记录 + * + * @param record + * @return + */ + @Override + public Boolean saveOrUpdateByReceiverNo(LklLedgerReceiver record) { + if (record == null || (StrUtil.isBlank(record.getLicense_no()) && StrUtil.isBlank(record.getContact_mobile()))) { + return false; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(record.getLicense_no())) { + queryWrapper.eq("license_no", record.getLicense_no()); + } + if (StrUtil.isNotBlank(record.getContact_mobile())) { + queryWrapper.eq("contact_mobile", record.getContact_mobile()); + } + + List existsRecordList = list(queryWrapper); + if (!CollectionUtil.isEmpty(existsRecordList) + && existsRecordList.get(0) != null + && existsRecordList.get(0).getId() > 0) { + // update + record.setId(existsRecordList.get(0).getId()); + return updateById(record); + } + + return save(record); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java new file mode 100644 index 00000000..69375c13 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.utils; + +import cn.hutool.core.util.StrUtil; +import com.lkl.laop.sdk.Config2; +import com.lkl.laop.sdk.LKLSDK; +import com.suisung.mall.common.exception.ApiException; +import com.suisung.mall.common.utils.I18nUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.springframework.core.io.ClassPathResource; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.*; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class LakalaUtil { + + /** + * 初始化 拉卡拉 SDK(全局只需设置一次) + * + * @return + */ + public static boolean initLKLSDK(String appId, String serialNo, String priKeyPath, String lklCerPath, String lklNotifyCerPath, String serverUrl) { + Config2 config = new Config2(); + config.setAppId(appId); + config.setSerialNo(serialNo); + config.setPriKey(getResourceFile(priKeyPath)); + config.setLklCer(getResourceFile(lklCerPath)); + config.setLklNotifyCer(getResourceFile(lklNotifyCerPath)); + config.setServerUrl(serverUrl); + return LKLSDK.init(config); + } + + /** + * 读取证书文件内容 + * + * @param fileName recource 文件夹下的路径,如:palyKey/wx/lakala_public_key.cer + * @return + */ + public static String getResourceFile(String fileName) { + StringBuilder stringBuilder = new StringBuilder(); + try (InputStream inputStream = new ClassPathResource(fileName).getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + String content = stringBuilder.toString(); + // log.info("证书内容:{}", content); + return content; + } catch (IOException e) { + // 记录异常信息 + log.error(e.getMessage()); + return ""; + } + } + + /** + * 获取 body 请求数据 + * + * @param request + * @return + */ + public static String getBody(HttpServletRequest request) { + InputStreamReader in = null; + try { + in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8); + StringBuffer bf = new StringBuffer(); + int len; + char[] chs = new char[1024]; + while ((len = in.read(chs)) != -1) { + bf.append(new String(chs, 0, len)); + } + return bf.toString(); + } catch (Exception e) { + log.error("请求头部取数据异常:{}", e); + throw new ApiException(I18nUtil._("获取请求数据失败!"), e); + } finally { + if (null != in) { + try { + in.close(); + } catch (Exception e) { + log.error("流关闭异常:{}", e); + } + } + } + } + + /** + * 获取证书信息 + * + * @param inputStream + * @return + */ + public static X509Certificate loadCertificate(InputStream inputStream) { + try { + CertificateFactory cf = CertificateFactory.getInstance("X509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); +// String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded()); +// System.out.println(publicKeyBase64); + cert.checkValidity(); + return cert; + } catch (CertificateExpiredException e) { + throw new RuntimeException("证书已过期", e); + } catch (CertificateNotYetValidException e) { + throw new RuntimeException("证书尚未生效", e); + } catch (CertificateException e) { + throw new RuntimeException("无效的证书", e); + } + } + + + /** + * 签名验证 + * + * @param certificate + * @param message + * @param signature + * @return + */ + public static boolean verify(X509Certificate certificate, byte[] message, String signature) { + try { + Signature sign = Signature.getInstance("SHA256withRSA"); + sign.initVerify(certificate); + sign.update(message); + byte[] signatureB = Base64.decodeBase64(signature); + return sign.verify(signatureB); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("当前Java环境不支持SHA256withRSA", e); + } catch (SignatureException e) { + throw new RuntimeException("签名验证过程发生了错误", e); + } catch (InvalidKeyException e) { + throw new RuntimeException("无效的证书", e); + } + } + + + /** + * 签名校验 + * + * @param authorization + * @param reqBody + * @param lklNotifyCerPath + * @return + */ + public static boolean verify(String authorization, String reqBody, String lklNotifyCerPath) { + try { + log.debug("拉卡拉 Authorization 内容:{}", authorization); + Map headerMap = getLakalaAuthorizationMap(authorization); + String timestamp = headerMap.get("timestamp"); + String nonceStr = headerMap.get("nonce_str"); + String signature = headerMap.get("signature"); + + X509Certificate lklNotifyCer = loadCertificate(new ClassPathResource(lklNotifyCerPath).getInputStream()); + if (StrUtil.isBlank(timestamp) || StrUtil.isBlank(nonceStr) || StrUtil.isBlank(signature) || lklNotifyCer == null) { + return false; + } + + String preSignDataStr = timestamp + "\n" + + nonceStr + "\n" + + reqBody + "\n"; + log.debug("拉卡拉签名明文内容:{}", preSignDataStr); + if (verify(lklNotifyCer, preSignDataStr.getBytes(StandardCharsets.UTF_8), signature)) { + log.debug("验签成功"); + return true; + } + + log.debug("验签失败"); + return false; + } catch (Exception e) { + log.error("验签发生异常:{}", e); + return false; + } + } + + /** + * 解析请求头中的认证签名等信息 + * 参考:https://o.lakala.com/#/home/document/detail?id=36 + * + * @param authorization 格式如下 + * LKLAPI-SHA256withRSA timestamp="1643271327", + * nonce_str="rQCbASKattHx", + * signature=" + * iPSycbakMt7AgjmwbtaweDVI/RLsQnGvOGiVM93haFkPpT/BxUprYx/GKFLQZebSQMvBfbeWinmnOJlqd3bXgye41BUAVmbItSTOzaQhNyS2kbDwXXGJWmT84aeJWHUB05BWB8ng + * /+X7jrPtsenC6aO7Xgh8jNylJlkU59TKCi7BPGbyHo6pAWJl/Bus0IQps1ay+Eo6Ks3Ins3COV7 + * /lmu5p5FD7TAZsfP+ZvMFObLJOrDQeBTMFKFFWj4ZkjNzNlQqZWlfLv4yLns + * /dKTDLDy5tRO5zwunW+li5YLcwOVf3tbevNFtg53WoBhQnwf838WNvY9zfRhOpCc4fBlWAA==" + * @return + */ + public static Map getLakalaAuthorizationMap(String authorization) { + Map map = new HashMap(); + authorization = authorization.trim(); + int bpos = authorization.indexOf(" "); + String authType = authorization.substring(0, bpos); + String[] typeArr = authType.split("-"); + if (typeArr.length > 1) { + map.put("signSystemCode", typeArr[0]); + map.put("signAlgorithm", typeArr[1]); + } + + String signInfo = authorization.substring(bpos + 1); + String[] infoArr = signInfo.split(","); + String[] var7 = infoArr; + int var8 = infoArr.length; + + for (int var9 = 0; var9 < var8; ++var9) { + String info = var7[var9]; + if (info.contains("=")) { + int fpos = info.indexOf("="); + String value = info.substring(fpos + 1).trim(); + value = value.substring(1, value.length() - 1); + map.put(info.substring(0, fpos).trim(), value); + } + } + + return map; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java index 051c5e30..514ec790 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java @@ -307,7 +307,7 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl + + + diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml new file mode 100644 index 00000000..3e060b7a --- /dev/null +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml @@ -0,0 +1,4 @@ + + + + diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml new file mode 100644 index 00000000..2b03205c --- /dev/null +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml @@ -0,0 +1,4 @@ + + + + From 18da67511e915f84024ec44ff8ff8c559ce6905c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 25 Apr 2025 00:19:48 +0800 Subject: [PATCH 04/39] =?UTF-8?q?shop=20=E9=A1=B9=E7=9B=AE=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=8B=89=E5=8D=A1=E6=8B=89=E7=9A=84=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suisung/mall/common/utils/UploadUtil.java | 44 ++++++++++++++++--- mall-pay/pom.xml | 3 +- mall-shop/pom.xml | 8 +++- .../service/impl/LakalaPayServiceImpl.java | 37 +++++++++++----- 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java index 5fe43aad..408caef2 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java @@ -3,14 +3,12 @@ package com.suisung.mall.common.utils; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.apache.tika.Tika; +import org.springframework.util.Base64Utils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.URLEncoder; +import java.net.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -25,14 +23,17 @@ public class UploadUtil { * token通过header传递的名称 */ public static final String TOKEN_HEADER_NAME = "Authorization"; - - // 除 text/* 外也需要设置输出编码的 content-type private final static List SET_CHARSET_CONTENT_TYPES = Arrays.asList( "application/json", "application/javascript" ); + public static void main(String[] args) { + String base64 = URLFileToBase64("http://gips3.baidu.com/it/u=1022347589,1106887837&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280"); + System.out.println(base64); + } + /** * 查看文件, 支持断点续传 * @@ -269,11 +270,40 @@ public class UploadUtil { // inputStream 用完之后,记得关闭 return inputStream; } catch (IOException e) { - e.printStackTrace(); + log.error("发生 I/O 错误: ", e.getMessage()); return null; } } + /** + * 将URL地址转换为Base64字符串 + * + * @param fileUrl + * @return + */ + public static String URLFileToBase64(String fileUrl) { + try { + URL url = new URL(fileUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + try (InputStream inputStream = connection.getInputStream()) { + byte[] buffer = new byte[inputStream.available()]; + inputStream.read(buffer); + return Base64Utils.encodeToString(buffer); + } finally { + connection.disconnect(); + } + } catch (MalformedURLException e) { + log.error("输入的 URL 格式不正确: {}", e.getMessage()); + } catch (IOException e) { + log.error("在连接或读取文件时发生 I/O 错误: {}", e.getMessage()); + } catch (Exception e) { + log.error("发生未知异常: {}", e.getMessage()); + } + return null; + } + /** * 下载图片到本地 * diff --git a/mall-pay/pom.xml b/mall-pay/pom.xml index c491acd1..44ace36e 100644 --- a/mall-pay/pom.xml +++ b/mall-pay/pom.xml @@ -1,5 +1,5 @@ - 4.0.0 @@ -161,6 +161,7 @@ org.springframework.boot spring-boot-maven-plugin + true diff --git a/mall-shop/pom.xml b/mall-shop/pom.xml index 9059009a..6f04abb6 100644 --- a/mall-shop/pom.xml +++ b/mall-shop/pom.xml @@ -286,13 +286,15 @@ ${project.basedir}/src/main/resources/lib/lkl-java-sdk-1.0.7.jar system + + com.github.javen205 IJPay-Core 2.8.0 compile - + @@ -363,6 +365,10 @@ org.springframework.boot spring-boot-maven-plugin + + + true + com.spotify diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java index c57da239..3a53d3d7 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaPayServiceImpl.java @@ -138,6 +138,9 @@ public class LakalaPayServiceImpl implements LakalaPayService { try { //3. 发送请求 String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq); + if (StrUtil.isBlank(responseStr)) { + throw new ApiException(I18nUtil._("下单无响应!")); + } //4. 响应 return JSONUtil.parseObj(responseStr); @@ -210,7 +213,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq); log.info("拉卡拉预下单响应数据:{}", responseStr); if (StrUtil.isBlank(responseStr)) { - return null; + throw new ApiException(I18nUtil._("下单无响应!")); } JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); @@ -257,6 +260,9 @@ public class LakalaPayServiceImpl implements LakalaPayService { try { //3. 发送请求 String responseStr = LKLSDK.httpPost(v3LabsQueryTradequeryRequest); + if (StrUtil.isBlank(responseStr)) { + throw new ApiException(I18nUtil._("交易查询无响应!")); + } JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); // || !lakalaRespJSON.getStr("code").equals("BBS00000") @@ -295,7 +301,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); if (shopStoreBase == null || StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) { log.error("缺少参数,退款交易失败!"); - return null; + throw new ApiException(I18nUtil._("缺少必要参数!")); } //2. 装配数据 @@ -313,6 +319,9 @@ public class LakalaPayServiceImpl implements LakalaPayService { try { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); + if (StrUtil.isBlank(responseStr)) { + throw new ApiException(I18nUtil._("退款交易失败!")); + } JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); @@ -353,6 +362,9 @@ public class LakalaPayServiceImpl implements LakalaPayService { try { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); + if (StrUtil.isBlank(responseStr)) { + throw new ApiException(I18nUtil._("账户余额查询无响应!")); + } JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); @@ -393,8 +405,10 @@ public class LakalaPayServiceImpl implements LakalaPayService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + if (StrUtil.isBlank(responseStr) + || lakalaRespJSON == null + || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._("文件上传无响应或失败!")); } return (JSONObject) lakalaRespJSON.get("respData"); @@ -448,10 +462,12 @@ public class LakalaPayServiceImpl implements LakalaPayService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); -// responseStr="{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}}"; -// lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (StrUtil.isBlank(responseStr) + || lakalaRespJSON == null + || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + throw new ApiException(I18nUtil._("分账申请失败!")); + // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} + } paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); @@ -479,7 +495,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { */ @Override public JSONObject applyLedgerMerNotify(HttpServletRequest request) { - log.info("商户分账申请业务回调收到通知"); + log.info("商户分账申请业务异步通知开始"); // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); @@ -511,7 +527,8 @@ public class LakalaPayServiceImpl implements LakalaPayService { reqData.getStr("entrustFilePath"), reqData.getStr("auditStatus"), reqData.getStr("auditStatusText"), - reqData.getStr("remark")); + reqData.getStr("remark") + ); if (success) { respData.put("retCode", lklSuccessCode); From 5f796adc02ec4807107a166862804fe1e9425c3c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 27 Apr 2025 10:23:22 +0800 Subject: [PATCH 05/39] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=E5=88=86=E8=B4=A6=E7=9B=B8=E5=85=B3=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/LakalaPayServiceImpl.java | 5 +- mall-shop/pom.xml | 8 + .../suisung/mall/shop/components/IpUtil.java | 2 +- .../lakala/controller/LakalaController.java | 11 +- .../lakala/controller/LklTkController.java | 4 +- ...aPayService.java => LakalaApiService.java} | 11 +- .../service/LklLedgerMemberService.java | 8 + .../LklLedgerMerReceiverBindService.java | 9 + .../service/LklLedgerReceiverService.java | 18 ++ ...iceImpl.java => LakalaApiServiceImpl.java} | 167 ++++++++++++------ .../impl/LklLedgerMemberServiceImpl.java | 18 ++ .../LklLedgerMerReceiverBindServiceImpl.java | 24 ++- .../impl/LklLedgerReceiverServiceImpl.java | 61 ++++++- ...klTkService.java => LklTkServiceImpl.java} | 15 +- .../admin/ShopPageBaseController.java | 5 + .../src/main/resources/bootstrap-local.yml | 2 +- .../src/main/resources/bootstrap-prod.yml | 40 +++-- .../payKey/lakala/dev/OP00000003_cert.cer | 21 +++ .../lakala/dev/OP00000003_private_key.pem | 28 +++ .../payKey/lakala/dev/lkl_notify_cert_v2.cer | 25 +++ .../resources/payKey/lakala/prod/api_cert.cer | 22 +++ .../payKey/lakala/prod/api_private_key.pem | 28 +++ .../payKey/lakala/prod/lkl_platform.cer | 25 +++ 23 files changed, 477 insertions(+), 80 deletions(-) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/{LakalaPayService.java => LakalaApiService.java} (94%) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/{LakalaPayServiceImpl.java => LakalaApiServiceImpl.java} (82%) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/{LklTkService.java => LklTkServiceImpl.java} (98%) create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_cert.cer create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_private_key.pem create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/lkl_notify_cert_v2.cer create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/api_cert.cer create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/api_private_key.pem create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/lkl_platform.cer diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index e964a00d..a7e1c528 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -449,11 +449,10 @@ public class LakalaPayServiceImpl implements LakalaPayService { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); + // {'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals("000000")) { throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); -// responseStr="{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}}"; -// lakalaRespJSON = JSONUtil.parseObj(responseStr); } paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); @@ -468,7 +467,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { return CommonResult.success(null, "提交成功,待审核中!"); } catch (SDKException e) { log.error("分账申请失败:", e); - throw new ApiException(I18nUtil._("申请失败!"), e); + throw new ApiException(I18nUtil._("分账申请失败!"), e); } } diff --git a/mall-shop/pom.xml b/mall-shop/pom.xml index 6f04abb6..b21aa70c 100644 --- a/mall-shop/pom.xml +++ b/mall-shop/pom.xml @@ -357,6 +357,10 @@ bootstrap.yml bootstrap-${profiles.active}.yml **/*.xml + **/*.crt + **/*.pem + **/*.p12 + **/*.cer @@ -381,6 +385,10 @@ ttf ttc + p12 + cer + pem + pfx diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java b/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java index 576411e9..6c4ef10b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java @@ -32,7 +32,7 @@ public class IpUtil implements ApplicationRunner { try { return searcher.search(ip); } catch (Exception e) { - log.error("IP 格式错误:{}", e); + log.error("IP:{} 格式错误:{}", ip, e); return null; } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java index 25a965d3..8eb44567 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java @@ -11,7 +11,7 @@ package com.suisung.mall.shop.lakala.controller; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.service.impl.BaseControllerImpl; -import com.suisung.mall.shop.lakala.service.LakalaPayService; +import com.suisung.mall.shop.lakala.service.LakalaApiService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.util.Base64Utils; @@ -28,7 +28,7 @@ import java.io.IOException; public class LakalaController extends BaseControllerImpl { @Resource - private LakalaPayService lakalaPayService; + private LakalaApiService lakalaPayService; @ApiOperation(value = "本地文件转base64", notes = "本地文件转base64") @RequestMapping(value = "/file2base64", method = RequestMethod.POST) @@ -37,6 +37,13 @@ public class LakalaController extends BaseControllerImpl { return str; } + + @ApiOperation(value = "获取银行卡的 BIN 信息", notes = "获取银行卡的 BIN 信息") + @RequestMapping(value = "/bankCardBin", method = RequestMethod.POST) + public JSONObject bankCardBin(@RequestBody JSONObject paramsJSON) { + return lakalaPayService.getBankCardBin(paramsJSON.getStr("bankCardNo")); + } + @ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请") @RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST) public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java index cac3f141..dcda37f2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java @@ -9,7 +9,7 @@ package com.suisung.mall.shop.lakala.controller; import com.suisung.mall.common.service.impl.BaseControllerImpl; -import com.suisung.mall.shop.lakala.service.impl.LklTkService; +import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,7 +24,7 @@ import javax.annotation.Resource; public class LklTkController extends BaseControllerImpl { @Resource - private LklTkService lklTkService; + private LklTkServiceImpl lklTkService; @ApiOperation(value = "请求获取token(商户进件)", notes = "请求获取token(商户进件)") @RequestMapping(value = "/token", method = RequestMethod.POST) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java similarity index 94% rename from mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java rename to mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 2166834e..b5334ce4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaPayService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -14,7 +14,7 @@ import com.suisung.mall.common.api.CommonResult; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -public interface LakalaPayService { +public interface LakalaApiService { Boolean initLKLSDK(); @@ -134,5 +134,14 @@ public interface LakalaPayService { */ JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request); + /** + * 获取银行卡信息 + * 参考:https://o.lakala.com/#/home/document/detail?id=387 + * + * @param bankCardNo + * @return + */ + JSONObject getBankCardBin(String bankCardNo); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index 4c11850f..38b607b4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -13,6 +13,14 @@ import com.suisung.mall.core.web.service.IBaseService; public interface LklLedgerMemberService extends IBaseService { + /** + * 根据银联商户号查询记录 + * + * @param merCupNo + * @return + */ + LklLedgerMember getByMerCupNo(String merCupNo); + /** * 根据银联商户号新增或修改记录 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java index 002e4e03..238f54f1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMerReceiverBindService.java @@ -21,6 +21,15 @@ public interface LklLedgerMerReceiverBindService extends IBaseService response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklServiceUrl(urlPath), header, formData, JSONObject.class); +// if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { +// return null; +// } +// JSONObject result = response.getBody(); +// if (result == null) { +// return null; +// } + + return null; + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java index 8a7b7b3b..f4dbb35d 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -26,6 +26,24 @@ import java.util.List; public class LklLedgerMemberServiceImpl extends BaseServiceImpl implements LklLedgerMemberService { + /** + * 根据银联商户号查询记录 + * + * @param merCupNo + * @return + */ + @Override + public LklLedgerMember getByMerCupNo(String merCupNo) { + if (StrUtil.isBlank(merCupNo)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", merCupNo); + queryWrapper.orderByAsc("id"); + return getOne(queryWrapper); + } + /** * 根据银联商户号新增或修改记录 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java index f9613a26..d0e097e6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java @@ -12,6 +12,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.lakala.mapper.LklLedgerMerReceiverBindMapper; @@ -30,13 +31,14 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("mer_cup_no", record.getMer_cup_no()); - queryWrapper.eq("receiver_no", record.getReceiver_no()); + queryWrapper.eq("mer_cup_no", record.getMer_cup_no()) + .eq("receiver_no", record.getReceiver_no()) + .eq("audit_status", CommonConstant.Enable); List existsRecordList = list(queryWrapper); if (!CollectionUtil.isEmpty(existsRecordList) && existsRecordList.get(0) != null @@ -46,7 +48,21 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", merCupNo) + .eq("receiver_no", receiverNo) + .eq("audit_status", CommonConstant.Enable); + + + return getOne(queryWrapper); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 80b3d4d3..09808878 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -9,8 +9,10 @@ package com.suisung.mall.shop.lakala.service.impl; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.lakala.mapper.LklLedgerReceiverMapper; @@ -40,9 +42,14 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl existsRecordList = list(queryWrapper); - if (!CollectionUtil.isEmpty(existsRecordList) + if (CollectionUtil.isNotEmpty(existsRecordList) && existsRecordList.get(0) != null && existsRecordList.get(0).getId() > 0) { // update @@ -50,6 +57,56 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("receiver_no", receiverNo).eq("status", CommonConstant.Enable); + queryWrapper.orderByAsc("id"); + + return getOne(queryWrapper); + } + + /** + * 根据条件查询记录 + * + * @param LicenseNo + * @param ContactMobile + * @param platformId + * @return + */ + @Override + public LklLedgerReceiver getByCondition(String LicenseNo, String ContactMobile, Long platformId) { + if (ObjectUtil.isEmpty(platformId)) { + platformId = 0L; + } + if (StrUtil.isBlank(LicenseNo) && StrUtil.isBlank(ContactMobile)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(LicenseNo)) { + queryWrapper.eq("license_no", LicenseNo); + } + if (StrUtil.isNotBlank(ContactMobile)) { + queryWrapper.eq("contact_mobile", ContactMobile); + } + + queryWrapper.eq("platform_id", platformId) + .eq("status", CommonConstant.Enable); + + return getOne(queryWrapper); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java similarity index 98% rename from mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java rename to mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index ed23b640..781fc7b9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -36,10 +36,13 @@ import java.util.HashMap; import java.util.Map; @Service -public class LklTkService { +public class LklTkServiceImpl { - private static final Logger log = LoggerFactory.getLogger(LklTkService.class); + private static final Logger log = LoggerFactory.getLogger(LklTkServiceImpl.class); @Value("${lakala.tk.server_url}") + private String tkServerUrl; + + @Value("${lakala.server_url}") private String serverUrl; @Value("${lakala.tk.client_id}") @@ -48,6 +51,9 @@ public class LklTkService { @Value("${lakala.tk.client_secret}") private String clientSecret; + @Value("${lakala.org_code}") + private String orgCode; + @Value("${spring.profiles.active}") private String profile; @@ -58,6 +64,10 @@ public class LklTkService { private RedisService redisService; protected String buildLklTkUrl(String urlPath) { + return tkServerUrl + urlPath; + } + + protected String buildLklServiceUrl(String urlPath) { return serverUrl + urlPath; } @@ -406,4 +416,5 @@ public class LklTkService { return jsonObject; } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/page/controller/admin/ShopPageBaseController.java b/mall-shop/src/main/java/com/suisung/mall/shop/page/controller/admin/ShopPageBaseController.java index 885ef5b9..7bccf062 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/page/controller/admin/ShopPageBaseController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/page/controller/admin/ShopPageBaseController.java @@ -24,6 +24,7 @@ import com.suisung.mall.shop.page.service.ShopPageBaseService; import com.suisung.mall.shop.product.service.ShopPageUserFormService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -44,6 +45,7 @@ import java.util.Map; * @author Xinze * @since 2021-06-11 */ +@Slf4j @Api(tags = "后台页面管理") @RestController @RequestMapping("/admin/shop/shop-page-base") @@ -230,6 +232,8 @@ public class ShopPageBaseController extends BaseControllerImpl { throw new ApiUserException(I18nUtil._("用户信息异常!")); } + log.info("ShopPageBaseController 用户信息:{}", JSONUtil.toJsonStr(user)); + ModelAndView view = new ModelAndView("diy"); Integer subsite_id = user.getSite_id(); @@ -244,6 +248,7 @@ public class ShopPageBaseController extends BaseControllerImpl { //Integer tpl_id = getParameter("tpl_id", 1012); Integer app_type = 3; + log.info("ShopPageBaseController 模版修改参数:{},{},{},{}", subsite_id, store_id, tpl_id, app_type); shopPageAppService.getModel(view, subsite_id, store_id, tpl_id, app_type); Map res = new HashMap<>(); diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 772c1e31..2a6dfea9 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -157,7 +157,7 @@ lakala: lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer #机构代码 org_code: 1 - #商户号 + #商户号, 测试商户号(未开通分账功能的):8222900539908Q9 merchant_no: 82229007392000A #终端号 term_no: D9296400 diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 32b090b4..4a18fc04 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -152,24 +152,42 @@ sf-express: enable: 2 #拉卡拉进件配置 lakala: + # #服务地址 + # server_url: https://s2.lakala.com + # #应用Id + # app_id: OP10000439 + # #商户证书序列号 + # serial_no: 1737359895636 + # #商户证书 + # api_cert_path: payKey/lakala/prod/api_cert.cer + # #商户私钥 + # api_pri_key_path: payKey/lakala/prod/api_private_key.pem + # #拉卡拉平台证书 + # lkl_platform_cer_path: payKey/lakala/prod/lkl_platform.cer + # #机构代码 + # org_code: 980688 + # #商户号 + # merchant_no: 8226330599900LN + # #终端号码,M0780629(B2B收银台) M0780798(专业化扫码) + # term_no: M0780798 #服务地址 - server_url: https://s2.lakala.com + server_url: https://test.wsmsd.cn/sit #应用Id - app_id: OP10000439 + app_id: OP00000003 #商户证书序列号 - serial_no: 1737359895636 + serial_no: 00dfba8194c41b84cf #商户证书 - api_cert_path: payKey/lakala/prod/api_cert.cer + api_cert_path: payKey/lakala/dev/OP00000003_cert.cer #商户私钥 - api_pri_key_path: payKey/lakala/prod/api_private_key.pem + api_pri_key_path: payKey/lakala/dev/OP00000003_private_key.pem #拉卡拉平台证书 - lkl_platform_cer_path: payKey/lakala/prod/lkl_platform.cer + lkl_platform_cer_path: payKey/lakala/dev/lkl_notify_cert_v2.cer #机构代码 - org_code: 980688 - #商户号 - merchant_no: 8226330599900LN - #终端号码,M0780629(B2B收银台) M0780798(专业化扫码) - term_no: M0780798 + org_code: 1 + #商户号, 测试商户号(未开通分账功能的):8222900539908Q9 + merchant_no: 82229007392000A + #终端号 + term_no: D9296400 #拉卡拉拓客进件配置 tk: #服务地址 diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_cert.cer b/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_cert.cer new file mode 100644 index 00000000..f85afd02 --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_cert.cer @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIJAN+6gZTEG4TPMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV +BAYTAlVTMREwDwYDVQQIEwhzaGFuZ2hhaTERMA8GA1UEBxMIc2hhbmdoYWkxFDAS +BgNVBAMUC2xha2FsYV8yMDIxMB4XDTIxMDYxODA3MjEzNFoXDTMxMDYxOTA3MjEz +NFowSTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCHNoYW5naGFpMREwDwYDVQQHEwhz +aGFuZ2hhaTEUMBIGA1UEAxQLbGFrYWxhXzIwMjEwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDvDBZyHUDndAGxrIcsCV2njhNO3vCEZotTaWYSYwtDvkcA +b1EjsBFabXZaKigpqFXk5XXNI3NIHP9M8XKzIgGvc65NpLAfRjVql8JiTvLyYd1g +IUcOXMInabu+oX7dQSI1mS8XzqaoVRhDZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si ++hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbWdhZ+NHwitnQwAJTLBFvfk28INM39G7XO +sXdVLfsooFdglVTOHpNuRiQAj9gShCCNrpGsNQxDiJIxE43qRsNsRwigyo6DPJk/ +klgDJa417E2wgP8VrwiXparO4FMzOGK15quuoD7DAgMBAAGjTDBKMAkGA1UdEwQC +MAAwEQYJYIZIAYb4QgEBBAQDAgTwMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggr +BgEFBQcDAgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAI21YYAlH+Pc1ISv +nbQrGqL8suGL0Hh/8hGaFfrJEJEKr9OeC8jElUhck2MTmfu/Y1lB7r8RBrhGPXi4 +kTXmB6ADs/9+ezNW3WXyFj7fhs3JcZ3mo33T9wyQySDKd//JrEtrTsc/s2PZ602y +qNmPomXSzjrlugaMyC7LI9sR44mc7sQnchjHoxrQFD5/usTFW72UQfYCORsQWYMt +0KKEyAcpRL51RE3xbX1WDtduFYGP62PbwLAn2nCL/j1wlF5hltWj7sditWqKgso5 +F8BTffn2Bb0RdsNxqwMy1cTPrWLeXVOqMDu3ge7hvoav8lZKTjk5Kmqhs7wNAQXK +mg9qSwo= +-----END CERTIFICATE----- diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_private_key.pem b/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_private_key.pem new file mode 100644 index 00000000..7d95886c --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/OP00000003_private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDvDBZyHUDndAGx +rIcsCV2njhNO3vCEZotTaWYSYwtDvkcAb1EjsBFabXZaKigpqFXk5XXNI3NIHP9M +8XKzIgGvc65NpLAfRjVql8JiTvLyYd1gIUcOXMInabu+oX7dQSI1mS8XzqaoVRhD +ZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si+hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbW +dhZ+NHwitnQwAJTLBFvfk28INM39G7XOsXdVLfsooFdglVTOHpNuRiQAj9gShCCN +rpGsNQxDiJIxE43qRsNsRwigyo6DPJk/klgDJa417E2wgP8VrwiXparO4FMzOGK1 +5quuoD7DAgMBAAECggEBANhmWOt1EAx3OBFf3f4/fEjylQgRSiqRqg8Ymw6KGuh4 +mE4Md6eW/B6geUOmZjVP7nIIR1wte28M0REWgn8nid8LGf+v1sB5DmIwgAf+8G/7 +qCwd8/VMg3aqgQtRp0ckb5OV2Mv0h2pbnltkWHR8LDIMwymyh5uCApbn/aTrCAZK +NXcPOyAn9tM8Bu3FHk3Pf24Er3SN+bnGxgpzDrFjsDSHjDFT9UMIc2WdA3tuMv9X +3DDn0bRCsHnsIw3WrwY6HQ8mumdbURk+2Ey3eRFfMYxyS96kOgBC2hqZOlDwVPAK +TPtS4hoq+cQ0sRaJQ4T0UALJrBVHa+EESgRaTvrXqAECgYEA+WKmy9hcvp6IWZlk +9Q1JZ+dgIVxrO65zylK2FnD1/vcTx2JMn73WKtQb6vdvTuk+Ruv9hY9PEsf7S8gH +STTmzHOUgo5x0F8yCxXFnfji2juoUnDdpkjtQK5KySDcpQb5kcCJWEVi9v+zObM0 +Zr1Nu5/NreE8EqUl3+7MtHOu1TMCgYEA9WM9P6m4frHPW7h4gs/GISA9LuOdtjLv +AtgCK4cW2mhtGNAMttD8zOBQrRuafcbFAyU9de6nhGwetOhkW9YSV+xRNa7HWTeI +RgXJuJBrluq5e1QGTIwZU/GujpNaR4Qiu0B8TodM/FME7htsyxjmCwEfT6SDYlke +MzTbMa9Q0DECgYBqsR/2+dvD2YMwAgZFKKgNAdoIq8dcwyfamUQ5mZ5EtGQL2yw4 +8zibHh/LiIxgUD1Kjk/qQgNsX45NP4iOc0mCkrgomtRqdy+rumbPTNmQ0BEVJCBP +scd+8pIgNiTvnWpMRvj7gMP0NDTzLI3wnnCRIq8WAtR2jZ0Ejt+ZHBziLQKBgQDi +bEe/zqNmhDuJrpXEXmO7fTv3YB/OVwEj5p1Z/LSho2nHU3Hn3r7lbLYEhUvwctCn +Ll2fzC7Wic1rsGOqOcWDS5NDrZpUQGGF+yE/JEOiZcPwgH+vcjaMtp0TAfRzuQEz +NzV8YGwxB4mtC7E/ViIuVULHAk4ZGZI8PbFkDxjKgQKBgG8jEuLTI1tsP3kyaF3j +Aylnw7SkBc4gfe9knsYlw44YlrDSKr8AOp/zSgwvMYvqT+fygaJ3yf9uIBdrIilq +CHKXccZ9uA/bT5JfIi6jbg3EoE9YhB0+1aGAS1O2dBvUiD8tJ+BjAT4OB0UDpmM6 +QsFLQgFyXgvDnzr/o+hQJelW +-----END PRIVATE KEY----- diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/lkl_notify_cert_v2.cer b/mall-shop/src/main/resources/payKey/lakala/dev/lkl_notify_cert_v2.cer new file mode 100644 index 00000000..12723ebe --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/lkl_notify_cert_v2.cer @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIGAXRTgcMnMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT +AkNOMRAwDgYDVQQIDAdCZWlKaW5nMRAwDgYDVQQHDAdCZWlKaW5nMRcwFQYDVQQK +DA5MYWthbGEgQ28uLEx0ZDEqMCgGA1UEAwwhTGFrYWxhIE9yZ2FuaXphdGlvbiBW +YWxpZGF0aW9uIENBMB4XDTIwMTAxMDA1MjQxNFoXDTMwMTAwODA1MjQxNFowZTEL +MAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaUppbmcxEDAOBgNVBAcMB0JlaUppbmcx +FzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMRkwFwYDVQQDDBBBUElHVy5MQUtBTEEu +Q09NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1zHL54HiI8d2sLJ +lwoQji3/ln0nsvfZ/XVpOjuB+1YR6/0LdxEDMC/hxI6iH2Rm5MjwWz3dmN/6BZeI +gwGeTOWJUZFARo8UduKrlhC6gWMRpAiiGC8wA8stikc5gYB+UeFVZi/aJ0WN0cpP +JYCvPBhxhMvhVDnd4hNohnR1L7k0ypuWg0YwGjC25FaNAEFBYP9EYUyCJjE//9Z7 +sMzHR9SJYCqqo6r9bOH9G6sWKuEp+osuAh+kJIxJMHfipw7w3tEcWG0hce9u/el4 +cYJtg8/PPMVoccKmeCzMvarr7jdKP4lenJbtwlgyfs+JgNu60KMUJH8RS72wC9NY +uFz09wIDAQABo4HVMIHSMIGSBgNVHSMEgYowgYeAFCnH4DkZPR6CZxRn/kIqVsMo +dJHpoWekZTBjMQswCQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpSmluZzEQMA4GA1UE +BwwHQmVpSmluZzEXMBUGA1UECgwOTGFrYWxhIENvLixMdGQxFzAVBgNVBAMMDkxh +a2FsYSBSb290IENBggYBaiUALIowHQYDVR0OBBYEFJ2Kx9YZfmWpkKFnC33C0r5D +K3rFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA +A4IBAQBZoeU0XyH9O0LGF9R+JyGwfU/O5amoB97VeM+5n9v2z8OCiIJ8eXVGKN9L +tl9QkpTEanYwK30KkpHcJP1xfVkhPi/cCMgfTWQ5eKYC7Zm16zk7n4CP6IIgZIqm +TVGsIGKk8RzWseyWPB3lfqMDR52V1tdA1S8lJ7a2Xnpt5M2jkDXoArl3SVSwCb4D +AmThYhak48M++fUJNYII9JBGRdRGbfJ2GSFdPXgesUL2CwlReQwbW4GZkYGOg9LK +CNPK6XShlNdvgPv0CCR08KCYRwC3HZ0y1F0NjaKzYdGNPrvOq9lA495ONZCvzYDo +gmsu/kd6eqxTs/JwdaIYr4sCMg8Z +-----END CERTIFICATE----- diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/api_cert.cer b/mall-shop/src/main/resources/payKey/lakala/prod/api_cert.cer new file mode 100644 index 00000000..0ddadbf3 --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/api_cert.cer @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIGAZSCuCxUMA0GCSqGSIb3DQEBBQUAMGAxFDASBgNVBAMM +C0xBS0FMQS1MQU9QMQswCQYDVQQGEwJDTjEXMBUGA1UECgwOTGFrYWxhIENvLixM +dGQxDzANBgNVBAsMBkxLTC1ZRjERMA8GA1UEBwwIc2hhbmdoYWkwHhcNMjUwMTIw +MDc1ODE1WhcNMzUwMTIwMDc1ODE1WjBgMRQwEgYDVQQDDAtMQUtBTEEtTEFPUDEL +MAkGA1UEBhMCQ04xFzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMQ8wDQYDVQQLDAZM +S0wtWUYxETAPBgNVBAcMCHNoYW5naGFpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAksIeSx7qKgmI7yFSglMBsty3ZoyC8qsCbLSWANwUPYikd5TPojB8 +43wJGJxOBOtDV8FL55q0zX3eQOE4BOVGcDMMUsZsAhy4ST46ne4e8CFVFHmM6TON +tS5Kla0hLjETpUjYStR8En534uoLYvnNPAI1CvmvWiUo+QGd3yc2SmyE+XB/8bKk +wiLjAauGyfb8m2BgCaoBIai+0IImInX2Xb85L0TAu0eYC6fX1T8BCupA4EVOpvLL +cM5P8nye4mibgS46lzlve1soC73W1vGAHnMw4epzk89NHKIMYEmZPoCU6jKuDbR0 +K73QwU0QZt9MSJnTdnWt/PeUJ8PzkhV0RQIDAQABo2AwXjAPBgNVHRMECDAGAQH/ +AgEAMB8GA1UdIwQYMBaAFG1rabju/OE7B3cPuQFZhs77ku5qMB0GA1UdDgQWBBRt +a2m47vzhOwd3D7kBWYbO+5LuajALBgNVHQ8EBAMCBsAwDQYJKoZIhvcNAQEFBQAD +ggEBACzdFsulR2X6HPKX+D2VU7msJyXRVWrAi06SV/zds8lPYUwSTEksbpWejD5L +ABftyv5DL7bU66vL80she2r5d+DbY+gB2hAgRHW+ymzfAqQJOcpciAXZHxc4orf+ +V4YtmLIRT0lg9rfU93D4S9fPe+HHMAmKFQXjnZNiv7DOar62MP0RrI74hWevaZao +gK8cMspxUW7H9VFvJvgGZRTRXVFHIvaPOpvlsdCYfUDomH2sWVLIiaSQoAVXxoET +c0HJB0er7Df2PSBSF/8bl9cVmp5HDB2YgtlfNKaFneGNN2WQtO3gl56heud8hGAe +F4YZkE8ML2mh83QqVSY4AkfWo+0= +-----END CERTIFICATE----- diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/api_private_key.pem b/mall-shop/src/main/resources/payKey/lakala/prod/api_private_key.pem new file mode 100644 index 00000000..68896c6c --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/api_private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCSwh5LHuoqCYjv +IVKCUwGy3LdmjILyqwJstJYA3BQ9iKR3lM+iMHzjfAkYnE4E60NXwUvnmrTNfd5A +4TgE5UZwMwxSxmwCHLhJPjqd7h7wIVUUeYzpM421LkqVrSEuMROlSNhK1HwSfnfi +6gti+c08AjUK+a9aJSj5AZ3fJzZKbIT5cH/xsqTCIuMBq4bJ9vybYGAJqgEhqL7Q +giYidfZdvzkvRMC7R5gLp9fVPwEK6kDgRU6m8stwzk/yfJ7iaJuBLjqXOW97WygL +vdbW8YAeczDh6nOTz00cogxgSZk+gJTqMq4NtHQrvdDBTRBm30xImdN2da3895Qn +w/OSFXRFAgMBAAECggEACN60qAOpUXscDJ/t9bSAoMfYSdlqPLJ7RgiwHEMw8fsl +PZj/56SYl8MyZYtk58U0X8RuCwR9swHNggxar2kQFc3wC7y0YHhN5xdcwZjXw9mv +47no+1tDUFUI6vz4yWrr7gx2DifDi/aa1lsg7w18CwlzHUO0BnXCgTJI0Wj0ThEj +k3AxCv41a4dwQW2EejaikMdzkWv7p9cG1cjJocBvaURg8RZrw2v1lqXx9iZb5Ywv +XkQP907AAnUn40bLgQ7hyUruxjKPzIM5ZjIER6PTtvGk1Uzt7Kj2YZZ4egYp0PXv +5fEJIcppeIyGfatEZ4U/ZmfA0L7+xtSY8kICndPSTQKBgQDHy5n6N6JdYyyrVFH/ +x4xTHwyiReOzw5Pz2K9uSxZM6pmDWfZexAxkpMycQotZYOk6GYDqml5XAiXAYVKn +i9FCEC6PnFRZ/v7TN3ag3k8eXwLrQu589+X0ppOizIp01IQ8AWAUr1tA/UcqLt8T +5XSHnoEDo9SY9Aw1kskY5TWoowKBgQC8CwRxfFNWk3Na+U4HgvVv8CSrB7rbkLUI +L11jNKFx4xms8uIjBrIencHsRAazoG73wMsY7MzbPtJKIFcXmSKjLFClJ6luN9np +1tYkWXF/nyo6L2IhCG7N28sxYa56XTR0lDnfkW+LiI7iaC1Z+XUtxoY3ZIL+0Dbv +wCfYS2I19wKBgQCtoRjtRJALzHYzZpHkUQx36BHYrBgYTy0yyuqaVRLKQU6rwfDD +pmiGxlkyqvni8L9+yE8qkoDN6IXaTDnCdVWjreBo2ZjMpTfbYuXrI4dqg3NL9NzB +KcZj+Kdw4YSpx04rv546G7KYJgREentPFSdR/MNt4GCPk/dQT4IH6pnZNQKBgQC2 +esKPFqURCPoSuIf+RhnDzPjoeBHe7KihDsXDddmN2WKbMQA+GUtU5qa/jqwqOHA3 +QQJWZ8XMpUQQ5x1dKyAv1NtVyg1jhhOUFwWsNJgtztl9qWnCwJo2byrZ+v8Eg9pZ +n1YiHNJwR87Q62PHQotyJossyf9NI+WL958zCMR/tQKBgCTDIKnfjq4riVLEOLxl +oGzGMowFTp9v8dyvrYj71C0ZDzLg/EH1tTQ4K46GIXJfyZvIATAIisC6R37KNmUA +w8f6YAOSS+iZBSZo36DoGIqJTYGyYgQDDftMsj/gxthgwRO5Zhwbn63ayJkWYyPy +C1RJ27LO8qX+3/s5pV7G9GlO +-----END PRIVATE KEY----- diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/lkl_platform.cer b/mall-shop/src/main/resources/payKey/lakala/prod/lkl_platform.cer new file mode 100644 index 00000000..c24d19c2 --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/lkl_platform.cer @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIGAXUrc4b4MA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT +AkNOMRAwDgYDVQQIDAdCZWlKaW5nMRAwDgYDVQQHDAdCZWlKaW5nMRcwFQYDVQQK +DA5MYWthbGEgQ28uLEx0ZDEqMCgGA1UEAwwhTGFrYWxhIE9yZ2FuaXphdGlvbiBW +YWxpZGF0aW9uIENBMB4XDTIwMTAxNTA4NDk1MloXDTMwMTAxMzA4NDk1MlowZTEL +MAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaUppbmcxEDAOBgNVBAcMB0JlaUppbmcx +FzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMRkwFwYDVQQDDBBBUElHVy5MQUtBTEEu +Q09NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwAXZw9lupWcFXouC +Nhm0DQT47Zf4KOIRF8rqT8Ps3pYzT8odROJ8rq4P+lciGrg29czpqrRM22yQktFr +itvcM7JlE6jFbGH3rycnvGvhRYU/j1N9k0ozm8oVwmKX357/OtGzNivBECGSnU9L +Bkp4Nm9M1K4cOwEuZ0xsQEthZjQYF0mDpnlWmVJL5i1Lq834atN2qrb/mzMHBNtD +JnqRV7rPL39lKpe7LJiitsC2JuW1UbWZZU1NNwA/rz2d83C+KD1DLJ0+sMYY2Q3T +OQ4BPAowDEwOH7XAXrHM/0kRm+ZeIFlwevEGIQWmMt1Ogz+AW4Iq0slINc4wOINK +vH9tHwIDAQABo4HVMIHSMIGSBgNVHSMEgYowgYeAFCnH4DkZPR6CZxRn/kIqVsMo +dJHpoWekZTBjMQswCQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpSmluZzEQMA4GA1UE +BwwHQmVpSmluZzEXMBUGA1UECgwOTGFrYWxhIENvLixMdGQxFzAVBgNVBAMMDkxh +a2FsYSBSb290IENBggYBaiUALIowHQYDVR0OBBYEFIya0Yc4OSBer55JLyA0AYe9 +m8mTMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA +A4IBAQCBEwOlk3mXigNv94Drn3dcaY2ml/y+8yNpAIuUhuBE00WFoqEX5lOatFy5 +fzdXuC12lBVQ8SjSm3aH7k2X0eXqDzkOHiur2ZBRKmJ++J4TeenuSUOjSIbQK/DT +vxaqFUjYwFSVCyizpy7wfU4wKt+jOuFb9LyULJ9lkM1dV9Kh7Lmd9+nlJYYuPEPU +LJkkVZqSALSiiJudXnTwlISjZTXEAkJpdIlMw+hvPTAkoG95B95M+OV/uLbItGK+ +qT4+RHWo8EbBDPQYo6J4QYHOxRlfMoGBMyrz6XDt7ELLmT7ld4aE02w6KQPfK3gq +kLDT+/STozvaNmXzBJh7J6KqxJBH +-----END CERTIFICATE----- \ No newline at end of file From c34aa3365e07a59f6b7f1e4b03eb9ea1b02a2a50 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 27 Apr 2025 17:37:05 +0800 Subject: [PATCH 06/39] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=20=E5=88=86=E8=B4=A6=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/lakala/LklLedgerMember.java | 2 +- .../lakala/controller/LakalaController.java | 3 +- .../service/LklLedgerMemberService.java | 9 +++++ .../service/impl/LakalaApiServiceImpl.java | 34 ++++++++++++++----- .../impl/LklLedgerMemberServiceImpl.java | 20 ++++++++++- .../LklLedgerMerReceiverBindServiceImpl.java | 4 +-- 6 files changed, 58 insertions(+), 14 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java index 9be106b4..22ef965e 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java @@ -42,7 +42,7 @@ public class LklLedgerMember implements Serializable { private String split_rule_source; private String ret_url; private String apply_id; - private String audit_status; + private Integer audit_status; private String audit_status_text; private String remark; private Long mch_id; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java index 8eb44567..3eb2a2b7 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java @@ -68,8 +68,9 @@ public class LakalaController extends BaseControllerImpl { return lakalaPayService.applyLedgerMerReceiverBind(paramsJSON); } + // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") - @RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST) + @RequestMapping(value = "/ledger/applyLedgerMerReceiverBindNotify", method = RequestMethod.POST) public JSONObject applyBindNotify(HttpServletRequest request) { return lakalaPayService.applyLedgerMerReceiverBindNotify(request); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index 38b607b4..a7cf5191 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -21,6 +21,15 @@ public interface LklLedgerMemberService extends IBaseService { */ LklLedgerMember getByMerCupNo(String merCupNo); + /** + * 根据申请单号和审核状态查询记录 + * + * @param applyId + * @param auditStatus + * @return + */ + LklLedgerMember getByApplyId(String applyId, Integer auditStatus); + /** * 根据银联商户号新增或修改记录 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 0a07075a..72a88d7b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -20,6 +20,7 @@ import com.lkl.laop.sdk.request.*; import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo; import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.feignService.ShopService; import com.suisung.mall.common.modules.lakala.LklLedgerMember; @@ -425,6 +426,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Override public CommonResult applyLedgerMer(JSONObject paramsJSON) { log.info("商户分账业务开通申请开始"); + + // TODO 判断是否已经申请过? // 1. 配置初始化 initLKLSDK(); @@ -449,11 +452,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + String domain = projectDomain; if (isProd()) { - projectDomain = projectDomain + "/api"; + domain += "/api"; } // 给拉卡拉通知的回调地址 - String retUrl = projectDomain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; req.setRetUrl(retUrl); paramsJSON.set("orderNo", req.getOrderNo()); @@ -502,6 +506,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Override public JSONObject applyLedgerMerNotify(HttpServletRequest request) { log.info("商户分账申请业务异步通知开始"); + // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); @@ -520,13 +525,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retMsg", "响应处理失败!"); if (paramsJSON != null) { -// JSONObject reqData = (JSONObject) paramsJSON.get("respData"); -// if (ObjectUtil.isEmpty(reqData)) { -// return respData; -// } + String applyId = paramsJSON.getStr("applyId"); + if (StrUtil.isBlank(applyId)) { + log.info("商户分账申请业务回调:applyId为空"); + respData.put("retMsg", "applyId为空!"); + return respData; + } + + if (lklLedgerMemberService.getByApplyId(applyId, CommonConstant.Enable) != null) { + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.info("商户分账申请业务回调:已处理成功,不需再重新处理"); + } // 更改本地分账记录状态数据 - Boolean success = lklLedgerMemberService.updateAuditResult(paramsJSON.getStr("applyId"), + Boolean success = lklLedgerMemberService.updateAuditResult(applyId, paramsJSON.getStr("merInnerNo"), paramsJSON.getStr("merCupNo"), paramsJSON.getStr("entrustFileName"), @@ -689,11 +702,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { String splitEntrustFileBase64 = UploadUtil.URLFileToBase64(paramsJSON.getStr("entrustFile")); // 这个是 url 地址,不是 base64 字节码 req.setEntrustFileName(fileName); + String domain = projectDomain; if (isProd()) { - projectDomain = projectDomain + "/api"; + domain += "/api"; } // 给拉卡拉通知的回调地址 - String retUrl = projectDomain + "/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify"; + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify"; req.setRetUrl(retUrl); // 文件上传到拉卡拉服务器 @@ -748,9 +762,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { + log.debug("分账绑定关系申请业务异步通知开始"); // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); + log.debug("分账绑定关系申请业务回调返回参数:{}", requestBody); boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java index f4dbb35d..88c1c102 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -44,6 +44,24 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("apply_id", applyId); + queryWrapper.eq("audit_status", auditStatus); + return getOne(queryWrapper); + } + /** * 根据银联商户号新增或修改记录 * @@ -57,7 +75,7 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("mer_cup_no", record.getMer_cup_no()); + queryWrapper.eq("mer_cup_no", record.getMer_cup_no()).eq("mch_id", record.getMch_id()); List existsRecordList = list(queryWrapper); if (!CollectionUtil.isEmpty(existsRecordList) && existsRecordList.get(0) != null diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java index d0e097e6..0c38a474 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java @@ -90,8 +90,8 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl Date: Mon, 28 Apr 2025 11:23:10 +0800 Subject: [PATCH 07/39] =?UTF-8?q?fix:=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=90=8E=E7=BC=80=E4=B8=8D=E6=94=AF=E6=8C=81=E5=A4=A7=E5=86=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suisung/mall/admin/oss/service/impl/OssServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java index a15b4e0b..a7fa5262 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java @@ -105,7 +105,8 @@ public class OssServiceImpl implements OssService { // 根据用户获取目录名 String dir = getUserDirName(user) + DateUtil.format(new Date(), "yyyyMMdd"); // 创建唯一文件名称 - String suffix = fileName.substring(fileName.lastIndexOf(".")); + assert fileName != null; + String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase(); String uploadName = IdUtil.simpleUUID() + suffix; String uploadPath = FILEPATH + "/" + dir + "/" + uploadName; From f335937d3e672ac89de424f562be18ffe432cd0b Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Mon, 28 Apr 2025 11:40:16 +0800 Subject: [PATCH 08/39] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=20=E5=88=86=E8=B4=A6=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/merch/ShopMerchEntry.java | 3 ++ .../LklTkAdminController.java} | 4 +- .../{ => mobile}/LakalaController.java | 2 +- .../controller/mobile/LklTkController.java | 40 +++++++++++++++++++ .../lakala/service/impl/LklTkServiceImpl.java | 29 +++++++++++--- .../store/service/ShopMerchEntryService.java | 9 +++++ .../impl/ShopMerchEntryServiceImpl.java | 13 +++++- 7 files changed, 90 insertions(+), 10 deletions(-) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/{LklTkController.java => admin/LklTkAdminController.java} (92%) rename mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/{ => mobile}/LakalaController.java (98%) create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java index 15376d3d..3737c076 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java @@ -210,6 +210,9 @@ public class ShopMerchEntry implements Serializable { @ApiModelProperty(value = "商家的代理商ID") private Long distributor_id; + @ApiModelProperty(value = "拉卡拉银联商户号(唯一)") + private String lkl_mer_cup_no; + @ApiModelProperty(value = "合同签署状态:0-无任何签署;1-一方签署;2-双方已签署;") private Integer signed_status; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/admin/LklTkAdminController.java similarity index 92% rename from mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java rename to mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/admin/LklTkAdminController.java index dcda37f2..44bfb7cb 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/admin/LklTkAdminController.java @@ -6,7 +6,7 @@ * Vestibulum commodo. Ut rhoncus gravida arcu. */ -package com.suisung.mall.shop.lakala.controller; +package com.suisung.mall.shop.lakala.controller.admin; import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; @@ -21,7 +21,7 @@ import javax.annotation.Resource; @Api(tags = "拉卡拉商户进件控制器") @RestController @RequestMapping("/admin/shop/lakala/tk") -public class LklTkController extends BaseControllerImpl { +public class LklTkAdminController extends BaseControllerImpl { @Resource private LklTkServiceImpl lklTkService; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java similarity index 98% rename from mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java rename to mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 3eb2a2b7..e1719698 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -6,7 +6,7 @@ * Vestibulum commodo. Ut rhoncus gravida arcu. */ -package com.suisung.mall.shop.lakala.controller; +package com.suisung.mall.shop.lakala.controller.mobile; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java new file mode 100644 index 00000000..0179718f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.controller.mobile; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +@Api(tags = "拉卡拉商户进件控制器") +@RestController +@RequestMapping("/mobile/shop/lakala/tk") +public class LklTkController extends BaseControllerImpl { + + @Resource + private LklTkServiceImpl lklTkService; + + + // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify + @ApiOperation(value = "拉卡拉进件申请异步回调通知", notes = "拉卡拉进件申请异步回调通知") + @RequestMapping(value = "/registrationMerchantNotify", method = {RequestMethod.POST, RequestMethod.GET}) + public JSONObject registrationMerchantNotify(HttpServletRequest request) { + return lklTkService.registrationMerchantNotify(request); + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 781fc7b9..c733ef64 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -20,6 +20,7 @@ import com.suisung.mall.common.utils.RestTemplateHttpUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.common.utils.UploadUtil; import com.suisung.mall.core.web.service.RedisService; +import com.suisung.mall.shop.lakala.utils.LakalaUtil; import com.suisung.mall.shop.store.service.ShopMerchEntryService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +32,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.io.File; import java.util.HashMap; import java.util.Map; @@ -201,20 +203,20 @@ public class LklTkServiceImpl { } } - + // TODO 咨询清楚 JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); bizContent.put("termNum", "1"); - bizContent.put("mcc", "1"); + bizContent.put("mcc", "12015"); // 超市的 code bizContent.put("fees", new JSONArray() {{ put(new JSONObject() {{ put("feeCode", "WECHAT"); - put("feeValue", 0.38); + put("feeValue", 0.20); }}); }}); - formData.put("bizContent", bizContent); + // 附件文件 JSONArray attachments = new JSONArray(); JSONObject ID_CARD_FRONT = updatePhoto(shopMerchEntry.getIndividual_id_images(), "ID_CARD_FRONT", true); if (ID_CARD_FRONT != null) { @@ -255,7 +257,6 @@ public class LklTkServiceImpl { if (BANK_CARD != null) { attachments.put(BANK_CARD); // 银行卡图片 } - formData.put("attchments", attachments); @@ -277,10 +278,26 @@ public class LklTkServiceImpl { // TODO 新增 lkl_ledger_member 数据, 等待异步审核通知,更改状态 - String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 + // String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 return Pair.of(true, "进件成功!"); } + /** + * 拉卡拉进件异步通知 + * + * @param request + * @return + */ + public JSONObject registrationMerchantNotify(HttpServletRequest request) { + log.debug("拉卡拉进件异步通知开始"); + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + log.debug("分账绑定关系申请业务回调返回参数:{}", requestBody); + + return new JSONObject().put("body", requestBody); + } + /** * 获取拉卡拉省市区编码 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java index 8b90279a..0f81f231 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java @@ -127,6 +127,15 @@ public interface ShopMerchEntryService { */ Boolean updateMerchEntryStoreStatus(String loginMobile, Integer storeStatus); + /** + * 更新商家入驻申请的拉卡拉商户号 + * + * @param loginMobile + * @param lklMerCupNo + * @return + */ + Boolean updateMerchEntryLklMerCupNo(String loginMobile, String lklMerCupNo); + /** * 更新商家入驻申请的店铺 ID * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java index 880bc269..4801005b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java @@ -678,7 +678,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); @@ -686,6 +686,17 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("login_mobile", loginMobile).set("lkl_mer_cup_no", lklMerCupNo); + return update(updateWrapper); + } + /** * 更新商家入驻申请的店铺 ID * From 17778c2e1c90e912ecfeb85aa71cf69f91cde3d0 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Wed, 30 Apr 2025 16:58:59 +0800 Subject: [PATCH 09/39] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=20=E5=88=86=E8=B4=A6=E6=8E=A5=E5=8F=A3bug,=20?= =?UTF-8?q?=E5=95=86=E5=AE=B6=E8=AE=A2=E5=8D=95=E5=88=97=E8=A1=A8=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/lakala/LklLedgerMember.java | 1 + .../common/modules/merch/ShopMerchEntry.java | 9 ++ .../common/utils/RestTemplateHttpUtil.java | 16 ++ mall-shop/pom.xml | 2 + .../controller/mobile/LakalaController.java | 1 - .../controller/mobile/LklTkController.java | 17 +- .../service/impl/LakalaApiServiceImpl.java | 4 +- .../lakala/service/impl/LklTkServiceImpl.java | 146 ++++++++++++++++-- .../store/service/ShopMerchEntryService.java | 16 +- .../impl/ShopMerchEntryServiceImpl.java | 42 ++++- .../src/main/resources/bootstrap-dev.yml | 2 + .../src/main/resources/bootstrap-local.yml | 4 +- .../src/main/resources/bootstrap-prod.yml | 2 + .../src/main/resources/bootstrap-test.yml | 2 + .../src/main/resources/bootstrap-uat.yml | 2 + .../mapper/order/ShopOrderBaseMapper.xml | 8 +- .../payKey/lakala/dev/tk_api_private_key.txt | 1 + .../payKey/lakala/dev/tk_api_public_key.txt | 1 + .../lakala/dev/tk_notify_private_key.txt | 1 + .../lakala/dev/tk_notify_public_key.txt | 1 + .../payKey/lakala/prod/tk_api_private_key.txt | 1 + .../payKey/lakala/prod/tk_api_public_key.txt | 1 + .../lakala/prod/tk_notify_private_key.txt | 1 + .../lakala/prod/tk_notify_public_key.txt | 1 + 24 files changed, 254 insertions(+), 28 deletions(-) create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/tk_api_private_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/tk_api_public_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_private_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_public_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/tk_api_private_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/tk_api_public_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_private_key.txt create mode 100644 mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_public_key.txt diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java index 22ef965e..4617fff7 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java @@ -44,6 +44,7 @@ public class LklLedgerMember implements Serializable { private String apply_id; private Integer audit_status; private String audit_status_text; + private String audit_resp; private String remark; private Long mch_id; private String version; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java index 3737c076..b6e32af2 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java @@ -213,6 +213,15 @@ public class ShopMerchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉银联商户号(唯一)") private String lkl_mer_cup_no; + @ApiModelProperty(value = "拉卡拉审核状态:1-已通过;2-未通过") + private Integer lkl_tk_audit_status; + + @ApiModelProperty(value = "拉卡拉进件请求参数") + private String lkl_tk_reg_params; + + @ApiModelProperty(value = "拉卡拉进件成功返回的JSON数据") + private String lkl_tk_reg_resp; + @ApiModelProperty(value = "合同签署状态:0-无任何签署;1-一方签署;2-双方已签署;") private Integer signed_status; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/RestTemplateHttpUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/RestTemplateHttpUtil.java index aa50bcfa..7a4215f8 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/RestTemplateHttpUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/RestTemplateHttpUtil.java @@ -91,6 +91,22 @@ public class RestTemplateHttpUtil { return response.getBody(); } + public static ResponseEntity sendPostBodyBackEntity(String url, JSONObject headers, JSONObject requestBody, Class responseType) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + httpHeaders.add(entry.getKey(), (String) entry.getValue()); + } + } + + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(requestBody, httpHeaders); + + ResponseEntity response = restTemplate.postForEntity(url, entity, responseType); + return response; + } + /** * 发送带 header 的 POST form-data 请求 * diff --git a/mall-shop/pom.xml b/mall-shop/pom.xml index b21aa70c..1942428b 100644 --- a/mall-shop/pom.xml +++ b/mall-shop/pom.xml @@ -361,6 +361,7 @@ **/*.pem **/*.p12 **/*.cer + **/*.txt @@ -389,6 +390,7 @@ cer pem pfx + txt diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index e1719698..106a1785 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -37,7 +37,6 @@ public class LakalaController extends BaseControllerImpl { return str; } - @ApiOperation(value = "获取银行卡的 BIN 信息", notes = "获取银行卡的 BIN 信息") @RequestMapping(value = "/bankCardBin", method = RequestMethod.POST) public JSONObject bankCardBin(@RequestBody JSONObject paramsJSON) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index 0179718f..6f39485f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -13,6 +13,8 @@ import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @@ -32,8 +34,19 @@ public class LklTkController extends BaseControllerImpl { // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify @ApiOperation(value = "拉卡拉进件申请异步回调通知", notes = "拉卡拉进件申请异步回调通知") @RequestMapping(value = "/registrationMerchantNotify", method = {RequestMethod.POST, RequestMethod.GET}) - public JSONObject registrationMerchantNotify(HttpServletRequest request) { - return lklTkService.registrationMerchantNotify(request); + public ResponseEntity registrationMerchantNotify(HttpServletRequest request) { + JSONObject resp = lklTkService.registrationMerchantNotify(request); + if (resp != null && resp.get("code").equals("200")) { + return new ResponseEntity<>(resp, HttpStatus.OK); + } + + return new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ApiOperation(value = "上传文件", notes = "上传文件") + @RequestMapping(value = "/uploadWithOCR", method = {RequestMethod.POST, RequestMethod.GET}) + public JSONObject uploadWithOCR(String fileURL) { + return lklTkService.uploadFileWithOcr("", fileURL, "ID_CARD_FRONT"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 72a88d7b..b8b1587e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -439,7 +439,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); req.setMerCupNo(paramsJSON.getStr("merCupNo")); req.setContactMobile(paramsJSON.getStr("contactMobile")); - req.setSplitLowestRatio(new BigDecimal(paramsJSON.getStr("splitLowestRatio"))); + // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 + // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) + req.setSplitLowestRatio(BigDecimal.valueOf(70)); String fileName = paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index c733ef64..acb1f521 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -32,8 +32,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import javax.crypto.Cipher; import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -56,6 +62,9 @@ public class LklTkServiceImpl { @Value("${lakala.org_code}") private String orgCode; + @Value("${lakala.tk.notify_pub_key_path}") + private String notifyPubKeyPath; + @Value("${spring.profiles.active}") private String profile; @@ -65,6 +74,41 @@ public class LklTkServiceImpl { @Autowired private RedisService redisService; + /** + * 拉卡拉异步通知数据公钥解密 + * + * @param pubKey Base64公钥 + * @param data Base64数据 + * @return 解密字符串 + */ + public String decryptNotifyData(String pubKey, String data) { + try { + Base64.Decoder decoder = Base64.getDecoder(); + byte[] keyBytes = decoder.decode(pubKey.getBytes()); + byte[] dataBytes = decoder.decode(data.getBytes()); + Cipher cipher = Cipher.getInstance("RSA"); + PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes)); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] cache; + for (int i = 0, offset = 0, length = dataBytes.length; length - offset > 0; i++, offset = i * 128) { + if (length - offset > 128) { + cache = cipher.doFinal(dataBytes, offset, 128); + } else { + cache = cipher.doFinal(dataBytes, offset, length - offset); + } + out.write(cache, 0, cache.length); + } + return out.toString(); + } catch (IllegalArgumentException e) { + System.err.println("Base64 解码时出现非法参数异常: " + e.getMessage()); + } catch (Exception e) { + // 捕获其他可能的异常,如 NoSuchAlgorithmException、NoSuchPaddingException、InvalidKeySpecException、InvalidKeyException、BadPaddingException 等 + System.err.println("解密过程中出现异常: " + e.getMessage()); + } + return null; + } + protected String buildLklTkUrl(String urlPath) { return tkServerUrl + urlPath; } @@ -77,6 +121,40 @@ public class LklTkServiceImpl { return "prod".equalsIgnoreCase(profile); } + public JSONObject uploadFileWithOcr(String fileBase64, String fileURL, String imgType) { + String authorization = getLklTkAuthorization(); + if (StrUtil.isBlank(authorization)) { + return JSONUtil.createObj().set("code", 500).set("msg", "获取拉卡拉token失败"); + } + + JSONObject header = new JSONObject(); + header.put("Authorization", authorization); + + String urlPath = "/sit/htkregistration/file/upload"; + if (isProd()) { + urlPath = "/registration/file/upload"; + } + + if (StrUtil.isBlank(fileBase64)) { + fileBase64 = UploadUtil.URLFileToBase64(fileURL); + } + + JSONObject requestBody = new JSONObject(); + requestBody.put("fileBase64", fileBase64); +// requestBody.put("file", fileBase64); + requestBody.put("imgType", imgType); + requestBody.put("sourcechnl", "0"); + requestBody.put("isOcr", "true"); + + + ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity("https://htkactvi.lakala.com/registration/file/upload", header, requestBody, JSONObject.class); + if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK || response.getBody() == null) { + return null; + } + + return response.getBody(); + } + /** * 请求获取token(商户进件) * @@ -94,7 +172,7 @@ public class LklTkServiceImpl { formData.put("client_id", clientId); formData.put("client_secret", clientSecret); - String response = RestTemplateHttpUtil.sendPostFormData(buildLklTkUrl("/oauth/token"), null, formData, String.class); + String response = RestTemplateHttpUtil.sendPostFormData(buildLklTkUrl("/sit/htkauth/oauth/token"), null, formData, String.class); if (ObjectUtil.isEmpty(response)) { return ""; } @@ -133,7 +211,7 @@ public class LklTkServiceImpl { JSONObject formData = new JSONObject(); formData.put("userNo", "29153396"); - formData.put("email", mchMobile + "@163.com"); + formData.put("email", shopMerchEntry.getEmail()); formData.put("busiCode", "B2B_SYT"); formData.put("merRegName", shopMerchEntry.getStore_name()); @@ -156,7 +234,7 @@ public class LklTkServiceImpl { formData.put("source", "H5"); - formData.put("larIdType", "01"); + formData.put("larIdType", "01"); // 01 身份证 ,02 护照,03 港澳通行证,04 台胞证,10 外国人永久居留身份证,11 港妨澳居民居住证,12 台湾居民居住证,13 执行事务合伙人,99 其它证件 String larName = isQy ? shopMerchEntry.getLegal_person_name() : shopMerchEntry.getContact_name(); String larIdCard = isQy ? shopMerchEntry.getLegal_person_id_number() : shopMerchEntry.getIndividual_id_number(); String larIdCardStart = isQy ? shopMerchEntry.getLegal_person_id_period_begin() : shopMerchEntry.getIndividual_id_period_begin(); @@ -277,9 +355,11 @@ public class LklTkServiceImpl { // 根据入驻商家的代理商或平台方,顺便新增一个接收方记录 - // TODO 新增 lkl_ledger_member 数据, 等待异步审核通知,更改状态 - // String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 - return Pair.of(true, "进件成功!"); + // 更改入驻记录的拉卡拉内部商户号和进件请求参数 + String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 + shopMerchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, merchantNo, formData.toString()); + + return Pair.of(true, "提交成功待审核!"); } /** @@ -290,12 +370,37 @@ public class LklTkServiceImpl { */ public JSONObject registrationMerchantNotify(HttpServletRequest request) { log.debug("拉卡拉进件异步通知开始"); - // 验签 - String authorization = request.getHeader("Authorization"); - String requestBody = LakalaUtil.getBody(request); - log.debug("分账绑定关系申请业务回调返回参数:{}", requestBody); + JSONObject respData = new JSONObject(); - return new JSONObject().put("body", requestBody); + // 解密请求参数 + String requestBody = LakalaUtil.getBody(request); + log.debug("拉卡拉进件异步通知返回参数:{}", requestBody); + if (StrUtil.isBlank(requestBody)) { + return new JSONObject().set("code", "500").set("message", "返回参数为空"); + } + + JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody); + if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) { + return new JSONObject().set("code", "500").set("message", "参数格式有误"); + } + + // 公钥解密出来的数据 + String data = decryptNotifyData(notifyPubKeyPath, reqBodyJSON.getStr("data")); + if (StrUtil.isBlank(data)) { + return new JSONObject().set("code", "500").set("message", "参数解密出错"); + } + log.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); + + // 逻辑处理 + JSONObject dataJSON = JSONUtil.parseObj(data); + if (respData.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo"))) { + return new JSONObject().set("code", "500").set("message", "参数解析出错"); + } + + String externalCustomerNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 + shopMerchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(externalCustomerNo, dataJSON.getStr("customerNo"), CommonConstant.Enable, data); + + return new JSONObject().set("code", "200").set("message", "成功"); } /** @@ -329,10 +434,15 @@ public class LklTkServiceImpl { countryName = areaNames[2]; } - String urlPath = "/organization"; - if (isBankArea) { - urlPath = "/organization/bank"; + String urlPath = "/sit/htkregistration/organization"; + if (isProd()) { + urlPath = "/registration/organization"; } + + if (isBankArea) { + urlPath += "/bank"; + } + String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { log.error("获取拉卡拉token失败"); @@ -417,13 +527,16 @@ public class LklTkServiceImpl { formData.put("sourcechnl", "0"); formData.put("isOcr", isOcr); - String urlPath = "/file/upload"; + String urlPath = "/sit/htkregistration/file/upload"; + if (isProd()) { + urlPath = "/registration/file/upload"; + } ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { return null; } JSONObject result = response.getBody(); - if (result == null) { + if (result.isEmpty()) { return null; } @@ -433,5 +546,4 @@ public class LklTkServiceImpl { return jsonObject; } - } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java index 0f81f231..d915c228 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java @@ -131,10 +131,24 @@ public interface ShopMerchEntryService { * 更新商家入驻申请的拉卡拉商户号 * * @param loginMobile + * @param lklAuditStatus * @param lklMerCupNo + * @param lklTkRegParams * @return */ - Boolean updateMerchEntryLklMerCupNo(String loginMobile, String lklMerCupNo); + Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklTkRegParams); + + /** + * 更新商家入驻申请的拉卡拉审核状态和响应数据 + * + * @param lklMerCupNo + * @param lklInnerMerNo + * @param lklAuditStatus + * @param lklTkRegResp + * @return + */ + Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, String lklTkRegResp); + /** * 更新商家入驻申请的店铺 ID diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java index 4801005b..d09bef9b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java @@ -687,13 +687,51 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("login_mobile", loginMobile).set("lkl_mer_cup_no", lklMerCupNo); + updateWrapper.eq("login_mobile", loginMobile); + if (ObjectUtil.isNotEmpty(lklAuditStatus)) { + updateWrapper.set("lkl_audit_status", lklAuditStatus); + } + if (StrUtil.isNotBlank(lklMerCupNo)) { + updateWrapper.set("lkl_mer_cup_no", lklMerCupNo); + } + if (StrUtil.isNotBlank(lklTkRegParams)) { + updateWrapper.set("lkl_tk_reg_params", lklTkRegParams); + } + return update(updateWrapper); + } + + /** + * 更新商家入驻申请的拉卡拉审核状态和响应数据 + * + * @param lklMerCupNo + * @param lklInnerMerNo + * @param lklAuditStatus + * @param lklTkRegResp + * @return + */ + @Override + public Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, String lklTkRegResp) { + if (StrUtil.isBlank(lklMerCupNo)) { + return false; + } + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("lkl_mer_cup_no", lklMerCupNo); + if (ObjectUtil.isNotEmpty(lklAuditStatus)) { + updateWrapper.set("lkl_audit_status", lklAuditStatus); + } + if (StrUtil.isNotBlank(lklInnerMerNo)) { + updateWrapper.set("lkl_mer_inner_no", lklInnerMerNo); + } + if (StrUtil.isNotBlank(lklTkRegResp)) { + updateWrapper.set("lkl_tk_reg_resp", lklTkRegResp); + } return update(updateWrapper); } diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index 46679eb3..5d1d3cb7 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -169,6 +169,8 @@ lakala: client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt + notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt + notify_pri_key_path: payKey/lakala/dev/tk_notify_private_key.txt #e签宝配置 esign: server_url: https://smlopenapi.esign.cn diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 2a6dfea9..a809dd65 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -164,11 +164,13 @@ lakala: # 拉卡拉拓客进件配置 tk: #服务地址 - server_url: https://test.wsmsd.cn/sit/htkauth + server_url: https://test.wsmsd.cn client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt + notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt + notify_pri_key_path: payKey/lakala/dev/tk_notify_private_key.txt #e签宝配置 esign: server_url: https://smlopenapi.esign.cn diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 4a18fc04..e9dea6ae 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -196,6 +196,8 @@ lakala: client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt + notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt + notify_pri_key_path: payKey/lakala/dev/tk_notify_private_key.txt #e签宝配置 esign: server_url: https://smlopenapi.esign.cn diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 396c824d..f358d360 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -173,6 +173,8 @@ lakala: client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt + notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt + notify_pri_key_path: payKey/lakala/dev/tk_notify_private_key.txt #e签宝配置 esign: server_url: https://smlopenapi.esign.cn diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 396c824d..f358d360 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -173,6 +173,8 @@ lakala: client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt + notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt + notify_pri_key_path: payKey/lakala/dev/tk_notify_private_key.txt #e签宝配置 esign: server_url: https://smlopenapi.esign.cn diff --git a/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml b/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml index 70aef115..1b90db8f 100644 --- a/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml +++ b/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml @@ -625,7 +625,9 @@ SELECT ob.order_id, ob.order_time, - oi.order_time + #{expireSeconds}*1000 as arrival_time, + + oi.order_time + #{expireSeconds}*1000 as arrival_time, + ob.order_product_amount, ob.order_payment_amount, ob.currency_id, @@ -714,12 +716,12 @@ - and arrival_time =]]> UNIX_TIMESTAMP() * 1000 + and (oi.order_time + #{expireSeconds}*1000) =]]> UNIX_TIMESTAMP() * 1000 - and arrival_time UNIX_TIMESTAMP() * 1000 + and (oi.order_time + #{expireSeconds}*1000) UNIX_TIMESTAMP() * 1000 diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_private_key.txt b/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_private_key.txt new file mode 100644 index 00000000..a17740cc --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_private_key.txt @@ -0,0 +1 @@ +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnlpXdmJcbZHxh3w3Ghy/5wXtUBQcFzRMXgw2d7uYjzAzbIQ/ZCAj6srWoN/obtkU+G62kgcpByGmiVtK4LS+BoelKM705SzV+mcr8mNmr2jwNq1SwDSfgVxx5z00FtXl3LnKvCujvGYOmx6+nX8h6IiyyLX6IP6cFaqpUXHsZVAgMBAAECgYA4NpeM7etJ48T6H4Y3LsWEJkH6UDQlgbIblsaQkstMmLtTgOebrzN28UNfd8njcu9FVOrHGclOKbK7L+1cOLiduWsZKc/c/gAy9wAR4EhoLvlerH9EEPiPWFxdEDbMxPqlkpqLOo+PxHrhTn4vU4CaPdJtL2ujKn7nmsUdUDWo8QJBANS1TlM6nhPt2XlzN5kGfsJ4kBYNjuLXNA2YdNuC2ttYvEXHJ9T70FN/GnRBBIZu47uHH3Ie5nfep+qMk6a8RP8CQQDMecIyI0z1kVt+tOfWKw2ZFLsi74708qTaeR4W1ABtkngj1+bxoWWXr3KqhjqJkWxnhioSfXqu7CScNzjdM1CrAkAQd+ESjI1EmbumrYb2cAxMXi05p98SLPs4uj8B58WuCda5yEuLL9vXOxX/PjFtfxRepn2GxmGtki2J+UxNMnJdAkAFoORjlO0tZU7rcfdfwdeh+xwbnhSFUZiQGv1lC3jnizybX/oPdK3jOwUhBIjf+IzPXLYTxDh4UC/BzRNXo235AkEAhgYBk6H7RU2iIuvwz1c6CtE1gJ8DvEp1F0KOMWMFB0KCpDXUToix0dlMz962FozYENi4X4zYQo6nFwlXeS3Pfw== \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_public_key.txt b/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_public_key.txt new file mode 100644 index 00000000..7f699e3a --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/tk_api_public_key.txt @@ -0,0 +1 @@ +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp5aV3ZiXG2R8Yd8Nxocv+cF7VAUHBc0TF4MNne7mI8wM2yEP2QgI+rK1qDf6G7ZFPhutpIHKQchpolbSuC0vgaHpSjO9OUs1fpnK/JjZq9o8DatUsA0n4Fccec9NBbV5dy5yrwro7xmDpsevp1/IeiIssi1+iD+nBWqqVFx7GVQIDAQAB \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_private_key.txt b/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_private_key.txt new file mode 100644 index 00000000..f8561c8f --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_private_key.txt @@ -0,0 +1 @@ +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALKb2r7+J9aS9/aiDblUUlkMfU6XdIasmEm/GWVOAoIS+CGV+qItHrZ2uIxbdHGlQY0HBGGnPYNUDGipzQtgrEpzWFXvBkmO1tVLdUE5ZuQ6/6pzFgGJTOi9+ujSKE4hbPbTJ4y+/1qqVLypSV51j7m2QZREns8biKzuxKNRzDZFAgMBAAECgYAXLWtq+n8/9I1x92CRirQu8xR1tOi9qzsN4tsQTtm7eGuzrAs8rV89bVWQfTO0pa3Gd8ElTPcKCkeb82D014Qz4z7sLz3reNeYXay8PbCCegQxUn7xzykwckziydKw4cCBZQkmyCYtUZcyf+C2Z+0dX6dTO3Z7+/se0ndJleAbFwJBAO9omFP3+lxxXQgyv99+IJTRFp+xWZnfjWREU8aZQXy+QU1LYCxMafpaIJMOu4qwo1XwfLKelAuLc2kLQMhrEkcCQQC+/Jie67sp744bw2dBWo8LrghvIaPxkH9Sgkce3qHUPx4cK+tF/GtfujB4kKDhpQb4nEJtLhPEBjslL0bWkc0TAkAoRHBylx/+EncyXM7W+XDjdvOWMo8+iVJPzgpFOhvAroNvS8FGUif1GtmlwnGa1zDx0Hw40uFVu8PSpDjmPNQbAkEAsHBpiv/aVB6kmY+HF8BSwIaR8iEQ9Tz58z6595HTzWJWLc6BN5G/nJtE5k0u4+byrsClOXpE9maPQ4YOmnHuEwJAIEYvcN2Ju3on5wglbH2b9889zzg1P9z/1GbFPpi2kZeOZre2HQfojoU686oGBdvDe0BK6+jgir1hzwfJBB7fvQ== \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_public_key.txt b/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_public_key.txt new file mode 100644 index 00000000..e035f0f4 --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/dev/tk_notify_public_key.txt @@ -0,0 +1 @@ +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCym9q+/ifWkvf2og25VFJZDH1Ol3SGrJhJvxllTgKCEvghlfqiLR62driMW3RxpUGNBwRhpz2DVAxoqc0LYKxKc1hV7wZJjtbVS3VBOWbkOv+qcxYBiUzovfro0ihOIWz20yeMvv9aqlS8qUledY+5tkGURJ7PG4is7sSjUcw2RQIDAQAB \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_private_key.txt b/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_private_key.txt new file mode 100644 index 00000000..a17740cc --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_private_key.txt @@ -0,0 +1 @@ +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnlpXdmJcbZHxh3w3Ghy/5wXtUBQcFzRMXgw2d7uYjzAzbIQ/ZCAj6srWoN/obtkU+G62kgcpByGmiVtK4LS+BoelKM705SzV+mcr8mNmr2jwNq1SwDSfgVxx5z00FtXl3LnKvCujvGYOmx6+nX8h6IiyyLX6IP6cFaqpUXHsZVAgMBAAECgYA4NpeM7etJ48T6H4Y3LsWEJkH6UDQlgbIblsaQkstMmLtTgOebrzN28UNfd8njcu9FVOrHGclOKbK7L+1cOLiduWsZKc/c/gAy9wAR4EhoLvlerH9EEPiPWFxdEDbMxPqlkpqLOo+PxHrhTn4vU4CaPdJtL2ujKn7nmsUdUDWo8QJBANS1TlM6nhPt2XlzN5kGfsJ4kBYNjuLXNA2YdNuC2ttYvEXHJ9T70FN/GnRBBIZu47uHH3Ie5nfep+qMk6a8RP8CQQDMecIyI0z1kVt+tOfWKw2ZFLsi74708qTaeR4W1ABtkngj1+bxoWWXr3KqhjqJkWxnhioSfXqu7CScNzjdM1CrAkAQd+ESjI1EmbumrYb2cAxMXi05p98SLPs4uj8B58WuCda5yEuLL9vXOxX/PjFtfxRepn2GxmGtki2J+UxNMnJdAkAFoORjlO0tZU7rcfdfwdeh+xwbnhSFUZiQGv1lC3jnizybX/oPdK3jOwUhBIjf+IzPXLYTxDh4UC/BzRNXo235AkEAhgYBk6H7RU2iIuvwz1c6CtE1gJ8DvEp1F0KOMWMFB0KCpDXUToix0dlMz962FozYENi4X4zYQo6nFwlXeS3Pfw== \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_public_key.txt b/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_public_key.txt new file mode 100644 index 00000000..7f699e3a --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/tk_api_public_key.txt @@ -0,0 +1 @@ +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp5aV3ZiXG2R8Yd8Nxocv+cF7VAUHBc0TF4MNne7mI8wM2yEP2QgI+rK1qDf6G7ZFPhutpIHKQchpolbSuC0vgaHpSjO9OUs1fpnK/JjZq9o8DatUsA0n4Fccec9NBbV5dy5yrwro7xmDpsevp1/IeiIssi1+iD+nBWqqVFx7GVQIDAQAB \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_private_key.txt b/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_private_key.txt new file mode 100644 index 00000000..f8561c8f --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_private_key.txt @@ -0,0 +1 @@ +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALKb2r7+J9aS9/aiDblUUlkMfU6XdIasmEm/GWVOAoIS+CGV+qItHrZ2uIxbdHGlQY0HBGGnPYNUDGipzQtgrEpzWFXvBkmO1tVLdUE5ZuQ6/6pzFgGJTOi9+ujSKE4hbPbTJ4y+/1qqVLypSV51j7m2QZREns8biKzuxKNRzDZFAgMBAAECgYAXLWtq+n8/9I1x92CRirQu8xR1tOi9qzsN4tsQTtm7eGuzrAs8rV89bVWQfTO0pa3Gd8ElTPcKCkeb82D014Qz4z7sLz3reNeYXay8PbCCegQxUn7xzykwckziydKw4cCBZQkmyCYtUZcyf+C2Z+0dX6dTO3Z7+/se0ndJleAbFwJBAO9omFP3+lxxXQgyv99+IJTRFp+xWZnfjWREU8aZQXy+QU1LYCxMafpaIJMOu4qwo1XwfLKelAuLc2kLQMhrEkcCQQC+/Jie67sp744bw2dBWo8LrghvIaPxkH9Sgkce3qHUPx4cK+tF/GtfujB4kKDhpQb4nEJtLhPEBjslL0bWkc0TAkAoRHBylx/+EncyXM7W+XDjdvOWMo8+iVJPzgpFOhvAroNvS8FGUif1GtmlwnGa1zDx0Hw40uFVu8PSpDjmPNQbAkEAsHBpiv/aVB6kmY+HF8BSwIaR8iEQ9Tz58z6595HTzWJWLc6BN5G/nJtE5k0u4+byrsClOXpE9maPQ4YOmnHuEwJAIEYvcN2Ju3on5wglbH2b9889zzg1P9z/1GbFPpi2kZeOZre2HQfojoU686oGBdvDe0BK6+jgir1hzwfJBB7fvQ== \ No newline at end of file diff --git a/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_public_key.txt b/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_public_key.txt new file mode 100644 index 00000000..e035f0f4 --- /dev/null +++ b/mall-shop/src/main/resources/payKey/lakala/prod/tk_notify_public_key.txt @@ -0,0 +1 @@ +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCym9q+/ifWkvf2og25VFJZDH1Ol3SGrJhJvxllTgKCEvghlfqiLR62driMW3RxpUGNBwRhpz2DVAxoqc0LYKxKc1hV7wZJjtbVS3VBOWbkOv+qcxYBiUzovfro0ihOIWz20yeMvv9aqlS8qUledY+5tkGURJ7PG4is7sSjUcw2RQIDAQAB \ No newline at end of file From 0f563493ef6662051c2920e0200942c5e49e5d49 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sat, 3 May 2025 19:07:41 +0800 Subject: [PATCH 10/39] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=95=86=E8=A1=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/esign/EsignPlatformInfo.java | 22 +- .../ShopMchEntry.java} | 11 +- .../EsignContractFillingFileServiceImpl.java | 42 ++-- .../impl/EsignContractServiceImpl.java | 50 ++--- .../lakala/service/impl/LklTkServiceImpl.java | 203 +++++++++--------- ....java => ShopMchEntryAdminController.java} | 12 +- ...oller.java => ShopMchEntryController.java} | 20 +- ...tryMapper.java => ShopMchEntryMapper.java} | 4 +- ...yService.java => ShopMchEntryService.java} | 8 +- ...Impl.java => ShopMchEntryServiceImpl.java} | 60 +++--- .../impl/ShopStoreBaseServiceImpl.java | 61 +++--- ...EntryMapper.xml => ShopMchEntryMapper.xml} | 2 +- 12 files changed, 247 insertions(+), 248 deletions(-) rename mall-common/src/main/java/com/suisung/mall/common/modules/{merch/ShopMerchEntry.java => store/ShopMchEntry.java} (95%) rename mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/{ShopMerchEntryAdminController.java => ShopMchEntryAdminController.java} (75%) rename mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/{ShopMerchEntryController.java => ShopMchEntryController.java} (88%) rename mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/{ShopMerchEntryMapper.java => ShopMchEntryMapper.java} (80%) rename mall-shop/src/main/java/com/suisung/mall/shop/store/service/{ShopMerchEntryService.java => ShopMchEntryService.java} (93%) rename mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/{ShopMerchEntryServiceImpl.java => ShopMchEntryServiceImpl.java} (92%) rename mall-shop/src/main/resources/mapper/store/{ShopMerchEntryMapper.xml => ShopMchEntryMapper.xml} (76%) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java index 3527672b..fa0adc35 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java @@ -47,6 +47,12 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "平台方营业执照公司名称") private String license_company; + @ApiModelProperty(value = "代理商的省/市/区,如:广东省/深圳市/福田区") + private String license_area; + + @ApiModelProperty(value = "代理商的省id/市id/区id,如:11000/11100/11101") + private String license_district_id; + @ApiModelProperty(value = "平台方营业执照公司详细地址") private String license_address; @@ -74,7 +80,7 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "收款账户名称") private String rec_acc_name; - @ApiModelProperty(value = "收款账户账户类型:1-个人;2-企业;") + @ApiModelProperty(value = "收款账户账户类型:1-个人(对私);2-企业(对公);") private Integer rec_acc_type; @ApiModelProperty(value = "收款账户证件号") @@ -95,17 +101,11 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "平台方公司维度") private String latitude; - @ApiModelProperty(value = "平台方公司店铺所在的省") - private String province_id; + @ApiModelProperty(value = "代理商等级:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理;") + private Integer level; - @ApiModelProperty(value = "平台方公司所在的市") - private String city_id; - - @ApiModelProperty(value = "平台方公司所在的县区") - private String county_id; - - @ApiModelProperty(value = "类型:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理;") - private Integer type; + @ApiModelProperty(value = "邀请码,后期跟收益有关") + private String invite_code; @ApiModelProperty(value = "记录状态:1-有效;2-无效;") private Integer status; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java similarity index 95% rename from mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java rename to mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index b6e32af2..2489279a 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -6,7 +6,7 @@ * Vestibulum commodo. Ut rhoncus gravida arcu. */ -package com.suisung.mall.common.modules.merch; +package com.suisung.mall.common.modules.store; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; @@ -25,8 +25,8 @@ import java.util.Date; @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("shop_mch_entry") -@ApiModel(value = "ShopMerchEntry 实体", description = "商家入驻信息表") -public class ShopMerchEntry implements Serializable { +@ApiModel(value = "ShopMchEntry 实体", description = "商家入驻信息表") +public class ShopMchEntry implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "自增ID") @@ -192,13 +192,16 @@ public class ShopMerchEntry implements Serializable { @ApiModelProperty(value = "结算银行地区,格式: 省份/城市/乡县") private String bank_area; + @ApiModelProperty(value = "结算账号类型:57-对公 58-对私") + private String account_type; + @ApiModelProperty(value = "入驻商家的收款账户号码") private String account_number; @ApiModelProperty(value = "入驻商家的收款账户姓名") private String account_holder_name; - @ApiModelProperty(value = "入驻商家的审批状态:1-已通过;2-未通过;3-待审核;") + @ApiModelProperty(value = "入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交审核;") private Integer approval_status; @ApiModelProperty(value = "入驻商家审批时的备注信息") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java index 85865d9a..88ba9d90 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java @@ -20,7 +20,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.esign.EsignContractFillingFile; import com.suisung.mall.common.modules.esign.EsignPlatformInfo; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.esign.mapper.EsignContractFillingFileMapper; @@ -32,7 +32,7 @@ import com.suisung.mall.shop.esign.utils.comm.EsignHttpResponse; import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; import com.suisung.mall.shop.page.service.OssService; -import com.suisung.mall.shop.store.service.ShopMerchEntryService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; @@ -70,7 +70,7 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl() {{ put("componentKey", "mch_company17"); - put("componentValue", shopMerchEntry.getContact_name()); + put("componentValue", shopMchEntry.getContact_name()); }}); } } @@ -234,7 +234,7 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl() {{ put("componentKey", "mch_store_name1"); - put("componentValue", shopMerchEntry.getStore_name()); + put("componentValue", shopMchEntry.getStore_name()); }}); list.add(new HashMap() {{ @@ -244,27 +244,27 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl() {{ put("componentKey", "mch_ratio"); - put("componentValue", shopMerchEntry.getSplit_ratio()); + put("componentValue", shopMchEntry.getSplit_ratio()); }}); list.add(new HashMap() {{ put("componentKey", "settlement_method"); - put("componentValue", shopMerchEntry.getSettlement_method()); + put("componentValue", shopMchEntry.getSettlement_method()); }}); list.add(new HashMap() {{ put("componentKey", "mch_address1"); - put("componentValue", shopMerchEntry.getStore_address()); + put("componentValue", shopMchEntry.getStore_address()); }}); list.add(new HashMap() {{ put("componentKey", "mch_bank1"); - put("componentValue", shopMerchEntry.getBank_name()); + put("componentValue", shopMchEntry.getBank_name()); }}); list.add(new HashMap() {{ put("componentKey", "mch_account_number1"); - put("componentValue", shopMerchEntry.getAccount_number()); + put("componentValue", shopMchEntry.getAccount_number()); }}); // 乙方公司名称 @@ -407,9 +407,9 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl { log.debug("###更改同步合同审核状态和下载地址###"); // 更改同步合同审核状态和下载地址 - if (!shopMerchEntryService.updateMerchEntrySignedStatusAndContractDownloadUrl(esignContract.getMch_mobile(), signFlowStatus, localFileUrl)) { + if (!shopMchEntryService.updateMerchEntrySignedStatusAndContractDownloadUrl(esignContract.getMch_mobile(), signFlowStatus, localFileUrl)) { log.error("###更改同步合同审核状态和下载地址失败###"); } }); @@ -527,8 +527,8 @@ public class EsignContractServiceImpl extends BaseServiceImpl response = RestTemplateHttpUtil.sendPostBodyBackEntity("https://htkactvi.lakala.com/registration/file/upload", header, requestBody, JSONObject.class); - if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK || response.getBody() == null) { - return null; + ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklServiceUrl(urlPath), header, requestBody, JSONObject.class); + if (ObjectUtil.isEmpty(response) + || response.getStatusCode() != HttpStatus.OK + || ObjectUtil.isEmpty(response.getBody())) { + return JSONUtil.createObj().set("code", 500).set("msg", "返回值有误!"); } + // {batchNo,status,url,showUrl,result{} } return response.getBody(); } @@ -204,77 +211,81 @@ public class LklTkServiceImpl { header.put("Authorization", getLklTkAuthorization()); // 获取商家入驻信息,组成请求参数 - ShopMerchEntry shopMerchEntry = shopMerchEntryService.getShopMerchEntryByCondition(mchMobile, null, CommonConstant.MCH_APPR_STA_PASS); - if (ObjectUtil.isEmpty(shopMerchEntry)) { + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, null, CommonConstant.MCH_APPR_STA_PASS); + if (ObjectUtil.isEmpty(shopMchEntry)) { return Pair.of(false, "商家入驻信息不存在"); } JSONObject formData = new JSONObject(); formData.put("userNo", "29153396"); - formData.put("email", shopMerchEntry.getEmail()); - formData.put("busiCode", "B2B_SYT"); - formData.put("merRegName", shopMerchEntry.getStore_name()); - Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMerchEntry.getEntity_type()); + formData.put("busiCode", "WECHAT_PAY");// WECHAT_PAY:专业化扫码;B2B_SYT:B2B收银台; + formData.put("email", shopMchEntry.getEmail()); + formData.put("merRegName", shopMchEntry.getStore_name()); + formData.put("merName", shopMchEntry.getStore_name()); + formData.put("merAddr", StringUtils.removeProvinceCityDistrict(shopMchEntry.getStore_address())); + + // 是企业类型商家 + Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()); String merType = isQy ? "TP_MERCHANT" : "TP_PERSONAL"; formData.put("merType", merType); - formData.put("merName", shopMerchEntry.getStore_name()); - formData.put("merAddr", StringUtils.removeProvinceCityDistrict(shopMerchEntry.getStore_address())); - - Map areaCode = getAreaCode(shopMerchEntry.getStore_area(), false); + Map areaCode = getAreaCode(shopMchEntry.getStore_area(), false); if (ObjectUtil.isNotEmpty(areaCode)) { formData.put("provinceCode", areaCode.get("provinceCode")); formData.put("cityCode", areaCode.get("cityCode")); formData.put("countyCode", areaCode.get("countyCode")); } - formData.put("longtude", shopMerchEntry.getStore_longitude()); //longitude 经度 - formData.put("latitude", shopMerchEntry.getStore_latitude()); + formData.put("longtude", shopMchEntry.getStore_longitude()); //longitude 经度 + formData.put("latitude", shopMchEntry.getStore_latitude()); formData.put("source", "H5"); formData.put("larIdType", "01"); // 01 身份证 ,02 护照,03 港澳通行证,04 台胞证,10 外国人永久居留身份证,11 港妨澳居民居住证,12 台湾居民居住证,13 执行事务合伙人,99 其它证件 - String larName = isQy ? shopMerchEntry.getLegal_person_name() : shopMerchEntry.getContact_name(); - String larIdCard = isQy ? shopMerchEntry.getLegal_person_id_number() : shopMerchEntry.getIndividual_id_number(); - String larIdCardStart = isQy ? shopMerchEntry.getLegal_person_id_period_begin() : shopMerchEntry.getIndividual_id_period_begin(); - String larIdCardEnd = isQy ? shopMerchEntry.getLegal_person_id_period_end() : shopMerchEntry.getIndividual_id_period_end(); + String larName = isQy ? shopMchEntry.getLegal_person_name() : shopMchEntry.getContact_name(); + String larIdCard = isQy ? shopMchEntry.getLegal_person_id_number() : shopMchEntry.getIndividual_id_number(); + String larIdCardStart = isQy ? shopMchEntry.getLegal_person_id_period_begin() : shopMchEntry.getIndividual_id_period_begin(); + String larIdCardEnd = isQy ? shopMchEntry.getLegal_person_id_period_end() : shopMchEntry.getIndividual_id_period_end(); + + // 法人相关信息 formData.put("larName", larName); formData.put("larIdCard", larIdCard); formData.put("larIdCardStart", larIdCardStart); // 身份证有效期开始时间 formData.put("larIdCardEnd", larIdCardEnd); // 身份证有效期结束时间 - formData.put("businessContent", shopMerchEntry.getSales_info()); + // 营业执照上的经营内容 + formData.put("businessContent", shopMchEntry.getSales_info()); // 营业执照信息 if (isQy) { - formData.put("licenseName", shopMerchEntry.getBiz_license_company()); - formData.put("licenseNo", shopMerchEntry.getBiz_license_number()); - formData.put("licenseDtStart", shopMerchEntry.getBiz_license_period_begin()); - formData.put("licenseDtEnd", shopMerchEntry.getBiz_license_period_end()); + formData.put("licenseName", shopMchEntry.getBiz_license_company()); + formData.put("licenseNo", shopMchEntry.getBiz_license_number()); + formData.put("licenseDtStart", shopMchEntry.getBiz_license_period_begin()); + formData.put("licenseDtEnd", shopMchEntry.getBiz_license_period_end()); } formData.put("contactMobile", mchMobile); - formData.put("contactName", shopMerchEntry.getContact_name()); + formData.put("contactName", shopMchEntry.getContact_name()); - formData.put("openningBankCode", shopMerchEntry.getBank_code());//结算账户开户⾏号 - formData.put("openningBankName", shopMerchEntry.getBank_name());//结算账户开户⾏名称 - formData.put("clearingBankCode", shopMerchEntry.getClearing_bank_code());//结算账户清算⾏号 + formData.put("openningBankCode", shopMchEntry.getBank_code());//结算账户开户⾏号 + formData.put("openningBankName", shopMchEntry.getBank_name());//结算账户开户⾏名称 + formData.put("clearingBankCode", shopMchEntry.getClearing_bank_code());//结算账户清算⾏号 - formData.put("accountNo", shopMerchEntry.getAccount_number()); //结算人银行卡号 - formData.put("accountName", shopMerchEntry.getAccount_holder_name()); //结算人账户名称 - formData.put("accountIdCard", shopMerchEntry.getLegal_person_id_number());//结算⼈证件号码(身份证) + formData.put("accountType", isQy ? "57" : "58"); //结算账户类型: 57 对公 58 对私 + formData.put("accountNo", shopMchEntry.getAccount_number()); //结算人银行卡号 + formData.put("accountName", shopMchEntry.getAccount_holder_name()); //结算人账户名称 + formData.put("accountIdCard", shopMchEntry.getLegal_person_id_number());//结算⼈证件号码(身份证) formData.put("settleType", "D1"); //结算类型,D0秒到,D1次日结算 formData.put("settlementType", "AUTOMATIC"); // 结算方式:MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持) - formData.put("accountType", isQy ? "57" : "58"); //结算账户类型: 57 对公 58 对私 //结算信息省份代码 - Map bankAreaCode = getAreaCode(shopMerchEntry.getBank_area(), true); + Map bankAreaCode = getAreaCode(shopMchEntry.getBank_area(), true); if (ObjectUtil.isNotEmpty(bankAreaCode)) { formData.put("settleProvinceCode", bankAreaCode.get("provinceCode")); formData.put("settleCityCode", bankAreaCode.get("cityCode")); - String[] bankAreaName = shopMerchEntry.getBank_area().split(","); + String[] bankAreaName = shopMchEntry.getBank_area().split(","); if (bankAreaName.length >= 2) { formData.put("settleProvinceName", bankAreaName[0]); formData.put("settleCityName", bankAreaName[1]); @@ -294,72 +305,69 @@ public class LklTkServiceImpl { }}); formData.put("bizContent", bizContent); - // 附件文件 + // 附件文件相关开始 JSONArray attachments = new JSONArray(); - JSONObject ID_CARD_FRONT = updatePhoto(shopMerchEntry.getIndividual_id_images(), "ID_CARD_FRONT", true); + JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", true); if (ID_CARD_FRONT != null) { attachments.put(ID_CARD_FRONT); // 身份证正面 } - JSONObject ID_CARD_BEHIND = updatePhoto(shopMerchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", true); + JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", true); if (ID_CARD_BEHIND != null) { attachments.put(ID_CARD_BEHIND); // 身份证国徽面 } - JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMerchEntry.getLegal_person_id_images(), "SETTLE_ID_CARD_FRONT", true); + JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "SETTLE_ID_CARD_FRONT", true); if (SETTLE_ID_CARD_FRONT != null) { attachments.put(SETTLE_ID_CARD_FRONT); // 结算人身份证正面 } - JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMerchEntry.getLegal_person_id_images2(), "SETTLE_ID_CARD_BEHIND", true); + JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "SETTLE_ID_CARD_BEHIND", true); if (SETTLE_ID_CARD_BEHIND != null) { attachments.put(SETTLE_ID_CARD_BEHIND); // 结算人身份证国徽面 } - JSONObject BUSINESS_LICENCE = updatePhoto(shopMerchEntry.getBiz_license_image(), "BUSINESS_LICENCE", true); + JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", true); if (BUSINESS_LICENCE != null) { attachments.put(BUSINESS_LICENCE); // 营业执照 } - JSONObject SHOP_OUTSIDE_IMG = updatePhoto(shopMerchEntry.getFront_facade_image(), "SHOP_OUTSIDE_IMG", false); + JSONObject SHOP_OUTSIDE_IMG = updatePhoto(shopMchEntry.getFront_facade_image(), "SHOP_OUTSIDE_IMG", false); if (SHOP_OUTSIDE_IMG != null) { attachments.put(SHOP_OUTSIDE_IMG); // 门店门面图片 } - JSONObject SHOP_INSIDE_IMG = updatePhoto(shopMerchEntry.getEnvironment_image(), "SHOP_INSIDE_IMG", false); + JSONObject SHOP_INSIDE_IMG = updatePhoto(shopMchEntry.getEnvironment_image(), "SHOP_INSIDE_IMG", false); if (SHOP_INSIDE_IMG != null) { attachments.put(SHOP_INSIDE_IMG); // 门店内部图片 } - JSONObject BANK_CARD = updatePhoto(shopMerchEntry.getBank_image(), "BANK_CARD", true); + JSONObject BANK_CARD = updatePhoto(shopMchEntry.getBank_image(), "BANK_CARD", true); if (BANK_CARD != null) { attachments.put(BANK_CARD); // 银行卡图片 } formData.put("attchments", attachments); + // 附件文件相关结束 - - String urlPath = "/sit/htkregistration/merchant"; - if (isProd()) { - urlPath = "/registration/merchant"; - } + String urlPath = isProd() ? "/registration/merchant" : "/sit/htkregistration/merchant"; ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - String errMsg = "请求分账系统出错!"; + String errMsg = "返回空或请求状态异常。"; if (ObjectUtil.isNotEmpty(response.getBody()) && ObjectUtil.isNotEmpty(response.getBody().getStr("message"))) { errMsg = response.getBody().getStr("message"); } return Pair.of(false, "进件失败:" + errMsg); } - // 根据入驻商家的代理商或平台方,顺便新增一个接收方记录 - - // 更改入驻记录的拉卡拉内部商户号和进件请求参数 String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 - shopMerchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, merchantNo, formData.toString()); + Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, merchantNo, formData.toString()); + if (!success) { + return Pair.of(false, "提交进件成功,但更新商户号失败!"); + } - return Pair.of(true, "提交成功待审核!"); + return Pair.of(true, "提交进件成功,请等待审核!"); } /** @@ -386,45 +394,46 @@ public class LklTkServiceImpl { // 公钥解密出来的数据 String data = decryptNotifyData(notifyPubKeyPath, reqBodyJSON.getStr("data")); + log.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); if (StrUtil.isBlank(data)) { return new JSONObject().set("code", "500").set("message", "参数解密出错"); } - log.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); // 逻辑处理 JSONObject dataJSON = JSONUtil.parseObj(data); - if (respData.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo"))) { + if (dataJSON.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo"))) { return new JSONObject().set("code", "500").set("message", "参数解析出错"); } - String externalCustomerNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 - shopMerchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(externalCustomerNo, dataJSON.getStr("customerNo"), CommonConstant.Enable, data); + // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 + String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 + Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merCupNo, dataJSON.getStr("customerNo"), CommonConstant.Enable, data); + if (!success) { + return new JSONObject().set("code", "500").set("message", "更新商户号失败"); + } + + // 根据入驻商家的代理商或平台方,顺便新增一个接收方记录 return new JSONObject().set("code", "200").set("message", "成功"); } /** - * 获取拉卡拉省市区编码 + * 获取拉卡拉店铺的(或银行的)省市区编码 * * @param areaName 省份/城市/乡县 * @return */ public Map getAreaCode(String areaName, Boolean isBankArea) { - if (StrUtil.isBlank(areaName)) { - return new HashMap() {{ - put("provinceCode", ""); - put("cityCode", ""); - put("countyCode", ""); - }}; - } + Map retMap = new HashMap() {{ + put("provinceCode", ""); + put("cityCode", ""); + put("countyCode", ""); + }}; + String[] areaNames = areaName.split("/"); - if (areaNames.length < 2) { - return new HashMap() {{ - put("provinceCode", ""); - put("cityCode", ""); - put("countyCode", ""); - }}; + if (StrUtil.isBlank(areaName) || areaNames.length < 2) { + return retMap; } String provinceName = areaNames[0]; @@ -434,29 +443,18 @@ public class LklTkServiceImpl { countryName = areaNames[2]; } - String urlPath = "/sit/htkregistration/organization"; - if (isProd()) { - urlPath = "/registration/organization"; - } - - if (isBankArea) { - urlPath += "/bank"; - } + String urlPath = isProd() ? "/registration/organization" : "/sit/htkregistration/organization"; + urlPath = isBankArea ? urlPath + "/bank" : urlPath; // 银行地区 String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { log.error("获取拉卡拉token失败"); - return new HashMap() {{ - put("provinceCode", ""); - put("cityCode", ""); - put("countyCode", ""); - }}; + return retMap; } JSONObject header = new JSONObject(); header.put("Authorization", getLklTkAuthorization()); - Map areaCodeMap = new HashMap<>(); // 省份列表 ResponseEntity response = RestTemplateHttpUtil.sendGetWithHeader(buildLklTkUrl(urlPath + "/1"), header, JSONArray.class); @@ -467,10 +465,11 @@ public class LklTkServiceImpl { JSONArray jsonArray = response.getBody(); if (CollUtil.isNotEmpty(jsonArray)) { + // 省份列表 for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), provinceName)) { provinceCode = jsonObject.getStr("code"); - areaCodeMap.put("provinceCode", provinceCode); + retMap.put("provinceCode", provinceCode); break; } } @@ -483,15 +482,14 @@ public class LklTkServiceImpl { for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), cityName)) { cityCode = jsonObject.getStr("code"); - areaCodeMap.put("cityCode", cityCode); + retMap.put("cityCode", cityCode); break; } } } } - - // 乡列表 + // 乡县列表 if (StrUtil.isNotBlank(cityCode)) { response = RestTemplateHttpUtil.sendGetWithHeader(buildLklTkUrl(urlPath + "/" + cityCode), header, JSONArray.class); jsonArray = response.getBody(); @@ -499,7 +497,7 @@ public class LklTkServiceImpl { for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), countryName)) { countyCode = jsonObject.getStr("code"); - areaCodeMap.put("countyCode", countyCode); + retMap.put("countyCode", countyCode); break; } } @@ -508,8 +506,7 @@ public class LklTkServiceImpl { } } - - return areaCodeMap; + return retMap; } public JSONObject updatePhoto(String fileUrl, String imgType, Boolean isOcr) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMerchEntryAdminController.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMchEntryAdminController.java similarity index 75% rename from mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMerchEntryAdminController.java rename to mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMchEntryAdminController.java index bdf640be..564cc227 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMerchEntryAdminController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/admin/ShopMchEntryAdminController.java @@ -11,7 +11,7 @@ package com.suisung.mall.shop.store.controller.admin; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.service.impl.BaseControllerImpl; -import com.suisung.mall.shop.store.service.ShopMerchEntryService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.RequestBody; @@ -24,10 +24,10 @@ import javax.annotation.Resource; @Api(tags = "店铺基础信息表") @RestController @RequestMapping("/admin/shop/merch") -public class ShopMerchEntryAdminController extends BaseControllerImpl { +public class ShopMchEntryAdminController extends BaseControllerImpl { @Resource - private ShopMerchEntryService shopMerchEntryService; + private ShopMchEntryService shopMchEntryService; /** * 商家申请入驻商城平台 @@ -38,20 +38,20 @@ public class ShopMerchEntryAdminController extends BaseControllerImpl { @ApiOperation(value = "后台-商家申请入驻分页列表", notes = "商家申请入驻分页列表") @RequestMapping(value = "/list", method = RequestMethod.POST) public CommonResult shopMerchEntryList(@RequestBody JSONObject shopMerchEntryJSON) { - return shopMerchEntryService.shopMerchEntryList(shopMerchEntryJSON.getStr("keyword"), shopMerchEntryJSON.getInt("page"), shopMerchEntryJSON.getInt("pageSize")); + return shopMchEntryService.shopMerchEntryList(shopMerchEntryJSON.getStr("keyword"), shopMerchEntryJSON.getInt("page"), shopMerchEntryJSON.getInt("pageSize")); } @ApiOperation(value = "后台-获取商家入驻资料详情", notes = "后台-获取商家入驻资料详情") @RequestMapping(value = "/detail", method = RequestMethod.POST) public CommonResult shopMerchEntryDetail(@RequestBody JSONObject jsonParam) { - return shopMerchEntryService.shopMerchEntryDetail(jsonParam.getLong("id"), "", null); + return shopMchEntryService.shopMerchEntryDetail(jsonParam.getLong("id"), "", null); } @ApiOperation(value = "商家入驻审批", notes = "商家入驻审批") @RequestMapping(value = "/approval", method = RequestMethod.POST) public CommonResult shopMerchEntryApproval(@RequestBody JSONObject jsonParam) { // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核; - return shopMerchEntryService.shopMerchEntryApproval(jsonParam.getLong("id"), jsonParam.getInt("approvalStatus"), jsonParam.getStr("approvalRemark"), jsonParam.getStr("approvalInvalidCol")); + return shopMchEntryService.shopMerchEntryApproval(jsonParam.getLong("id"), jsonParam.getInt("approvalStatus"), jsonParam.getStr("approvalRemark"), jsonParam.getStr("approvalInvalidCol")); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMerchEntryController.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java similarity index 88% rename from mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMerchEntryController.java rename to mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java index 7f6d8e32..976a4cab 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMerchEntryController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java @@ -10,11 +10,11 @@ package com.suisung.mall.shop.store.controller.mobile; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.service.impl.BaiduMapServiceImpl; import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; -import com.suisung.mall.shop.store.service.ShopMerchEntryService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; @@ -26,10 +26,10 @@ import java.util.Map; @Api(tags = "店铺基础信息表") @RestController @RequestMapping("/mobile/shop/merch") -public class ShopMerchEntryController extends BaseControllerImpl { +public class ShopMchEntryController extends BaseControllerImpl { @Resource - private ShopMerchEntryService shopMerchEntryService; + private ShopMchEntryService shopMchEntryService; @Resource private EsignContractFillingFileService esignContractFillingFileService; @@ -47,26 +47,26 @@ public class ShopMerchEntryController extends BaseControllerImpl { @ApiOperation(value = "店铺主营分类(类目)", notes = "店铺主营分类(类目)") @RequestMapping(value = "/business/category", method = RequestMethod.POST) public CommonResult shopStoreBusinessCategoryList() { - return shopMerchEntryService.storeBusinessCategoryList(); + return shopMchEntryService.storeBusinessCategoryList(); } @ApiOperation(value = "商家申请入驻商城平台", notes = "商家申请入驻商城平台") @RequestMapping(value = "/apply", method = RequestMethod.POST) public CommonResult shopMerchEntryApply(@RequestBody JSONObject shopMerchEntryJSON) { - return shopMerchEntryService.shopMerchEntryApply(shopMerchEntryJSON); + return shopMchEntryService.shopMerchEntryApply(shopMerchEntryJSON); } @ApiOperation(value = "获取商家入驻资料详情", notes = "获取商家入驻资料详情") @RequestMapping(value = "/detail", method = RequestMethod.POST) public CommonResult shopMerchEntryDetail(@RequestBody JSONObject jsonParam) { - return shopMerchEntryService.shopMerchEntryDetail(null, jsonParam.getStr("mobile"), null); + return shopMchEntryService.shopMerchEntryDetail(null, jsonParam.getStr("mobile"), null); } @ApiOperation(value = "通过手机号mobile获取商家入驻审核状态", notes = "通过手机号获取商家入驻审核状态,远程调用用途") @RequestMapping(value = "/approval/status", method = RequestMethod.POST) public Integer shopMerchEntryApprovalStatus(@RequestBody JSONObject jsonParam) { // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请; - ShopMerchEntry record = shopMerchEntryService.shopMerchEntryApprovalInfo(jsonParam.getStr("mobile")); + ShopMchEntry record = shopMchEntryService.shopMerchEntryApprovalInfo(jsonParam.getStr("mobile")); if (record == null || record.getApproval_status() == null) { return 4; } @@ -78,7 +78,7 @@ public class ShopMerchEntryController extends BaseControllerImpl { @RequestMapping(value = "/fresh/approval/status", method = RequestMethod.POST) public CommonResult shopMerchEntryApprovalStatus2(@RequestBody JSONObject jsonParam) { // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请; - ShopMerchEntry record = shopMerchEntryService.shopMerchEntryApprovalInfo(jsonParam.getStr("mobile")); + ShopMchEntry record = shopMchEntryService.shopMerchEntryApprovalInfo(jsonParam.getStr("mobile")); Map result = new HashMap<>(); if (record == null || record.getApproval_status() == null) { // 配合前端的要求,没有申请过入驻商城平台的时候,返回未申请状态 @@ -103,7 +103,7 @@ public class ShopMerchEntryController extends BaseControllerImpl { @ApiOperation(value = "商家重新申请入驻商城平台", notes = "商家申请入驻材料被驳回的时候,修正材料,重新申请入驻") @RequestMapping(value = "/re-apply", method = RequestMethod.POST) public CommonResult shopMerchEntryReApply(@RequestBody JSONObject shopMerchEntryJSON) { - return shopMerchEntryService.shopMerchEntryReApply(shopMerchEntryJSON); + return shopMchEntryService.shopMerchEntryReApply(shopMerchEntryJSON); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMerchEntryMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMchEntryMapper.java similarity index 80% rename from mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMerchEntryMapper.java rename to mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMchEntryMapper.java index 68c7a32f..a40c2a4e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMerchEntryMapper.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/mapper/ShopMchEntryMapper.java @@ -9,9 +9,9 @@ package com.suisung.mall.shop.store.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.modules.store.ShopMchEntry; import org.springframework.stereotype.Component; @Component -public interface ShopMerchEntryMapper extends BaseMapper { +public interface ShopMchEntryMapper extends BaseMapper { } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java similarity index 93% rename from mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java rename to mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index d915c228..d3374586 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMerchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -10,12 +10,12 @@ package com.suisung.mall.shop.store.service; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.modules.store.ShopMchEntry; import org.springframework.data.util.Pair; import java.util.List; -public interface ShopMerchEntryService { +public interface ShopMchEntryService { /** * 获取店铺的经营类目列表 @@ -96,7 +96,7 @@ public interface ShopMerchEntryService { * @param loginMobile * @return */ - ShopMerchEntry shopMerchEntryApprovalInfo(String loginMobile); + ShopMchEntry shopMerchEntryApprovalInfo(String loginMobile); /** * 根据商家手机号、营业执照、审批状态获取有效的商家入驻申请记录 @@ -106,7 +106,7 @@ public interface ShopMerchEntryService { * @param approvalStatus * @return */ - ShopMerchEntry getShopMerchEntryByCondition(String loginMobile, String bizLicenseNumber, Integer approvalStatus); + ShopMchEntry getShopMerchEntryByCondition(String loginMobile, String bizLicenseNumber, Integer approvalStatus); /** * 根据商家注册的手机号,更新合同签署状态和合同下载地址 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java similarity index 92% rename from mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java rename to mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index d09bef9b..3c2b385c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -19,7 +19,7 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.constant.CommonConstant; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.utils.BankUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.common.utils.phone.PhoneNumberUtils; @@ -31,8 +31,8 @@ import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; import com.suisung.mall.shop.message.service.ShopMessageTemplateService; -import com.suisung.mall.shop.store.mapper.ShopMerchEntryMapper; -import com.suisung.mall.shop.store.service.ShopMerchEntryService; +import com.suisung.mall.shop.store.mapper.ShopMchEntryMapper; +import com.suisung.mall.shop.store.service.ShopMchEntryService; import com.suisung.mall.shop.store.service.ShopStoreBaseService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -51,7 +51,7 @@ import java.util.Map; */ @Slf4j @Service -public class ShopMerchEntryServiceImpl extends BaseServiceImpl implements ShopMerchEntryService { +public class ShopMchEntryServiceImpl extends BaseServiceImpl implements ShopMchEntryService { @Resource private AccountBaseConfigService accountBaseConfigService; @@ -127,7 +127,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); if (StrUtil.isNotBlank(keyword)) { queryWrapper.like("store_name", keyword); } @@ -353,7 +353,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl listPage = lists(queryWrapper, pageIndex, pageSize); + Page listPage = lists(queryWrapper, pageIndex, pageSize); return CommonResult.success(listPage); } @@ -375,7 +375,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); if (ObjectUtil.isNotEmpty(recordId)) { queryWrapper.eq("id", recordId); } @@ -389,12 +389,12 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl recordList = list(queryWrapper); + List recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return CommonResult.success(null, "暂无申请记录!"); } - ShopMerchEntry record = recordList.get(0); + ShopMchEntry record = recordList.get(0); // 试试更新入驻表的合同下载地址和合同签署状态 updateMerchEntrySignedStatusAndContractDownloadUrl(record); @@ -407,7 +407,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); if (approvalStatus.equals(CommonConstant.Enable) && StrUtil.isBlank(approvalRemark)) { // 审核通过 approvalRemark = "审核通过,后续将向您发起签署电子合同流程。"; @@ -524,7 +524,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); if (StrUtil.isNotBlank(mobile) && StrUtil.isBlank(bizLicenseNumber)) { queryWrapper.eq("login_mobile", mobile); boolean isApplied = count(queryWrapper) > 0; @@ -561,9 +561,9 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("login_mobile", mobile).select("approval_status").orderByAsc("id"); - List recordList = list(queryWrapper); + List recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return 0; } @@ -579,22 +579,22 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("login_mobile", loginMobile) .select("id", "approval_status", "approval_remark", "login_mobile", "approval_invalid_col", "signed_status", "contract_download_url", "store_status") .orderByAsc("id"); - List recordList = list(queryWrapper); + List recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return null; } - ShopMerchEntry record = recordList.get(0); + ShopMchEntry record = recordList.get(0); // 试试更新入驻表的合同下载地址和合同签署状态 updateMerchEntrySignedStatusAndContractDownloadUrl(record); @@ -611,12 +611,12 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("status", CommonConstant.Enable).orderByAsc("id"); if (StrUtil.isNotBlank(loginMobile)) { queryWrapper.eq("login_mobile", loginMobile); @@ -632,7 +632,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl recordList = list(queryWrapper); + List recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return null; } @@ -654,7 +654,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("login_mobile", loginMobile); if (ObjectUtil.isNotEmpty(signedStatus)) { @@ -681,7 +681,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("login_mobile", loginMobile).set("store_status", storeStatus); return update(updateWrapper); } @@ -692,7 +692,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("login_mobile", loginMobile); if (ObjectUtil.isNotEmpty(lklAuditStatus)) { updateWrapper.set("lkl_audit_status", lklAuditStatus); @@ -721,7 +721,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("lkl_mer_cup_no", lklMerCupNo); if (ObjectUtil.isNotEmpty(lklAuditStatus)) { updateWrapper.set("lkl_audit_status", lklAuditStatus); @@ -748,7 +748,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl() + return update(new UpdateWrapper() .eq("id", id) .set("store_id", storeId)); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java index bc9312b4..2946ad80 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java @@ -35,7 +35,6 @@ import com.suisung.mall.common.modules.base.*; import com.suisung.mall.common.modules.distribution.ShopDistributionPlantformUser; import com.suisung.mall.common.modules.invoicing.InvoicingCustomerLevel; import com.suisung.mall.common.modules.invoicing.InvoicingWarehouseBase; -import com.suisung.mall.common.modules.merch.ShopMerchEntry; import com.suisung.mall.common.modules.page.ShopPageBase; import com.suisung.mall.common.modules.pay.PayUserResource; import com.suisung.mall.common.modules.plantform.ShopPlantformSubsite; @@ -171,7 +170,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl districtList = shopBaseDistrictService.getFullDistrictByDistrictCode(shopMerchEntry.getCounty_id()); + List districtList = shopBaseDistrictService.getFullDistrictByDistrictCode(shopMchEntry.getCounty_id()); shopStoreBase.setStore_district_id(shopBaseDistrictService.joinDistrict(districtList, 1, true, "/")); shopStoreBase.setStore_area(shopBaseDistrictService.joinDistrict(districtList, 2, true, "/")); - shopStoreBase.setStore_address(shopMerchEntry.getStore_address()); - shopStoreBase.setStore_longitude(shopMerchEntry.getStore_longitude()); - shopStoreBase.setStore_latitude(shopMerchEntry.getStore_latitude()); + shopStoreBase.setStore_address(shopMchEntry.getStore_address()); + shopStoreBase.setStore_longitude(shopMchEntry.getStore_longitude()); + shopStoreBase.setStore_latitude(shopMchEntry.getStore_latitude()); shopStoreBase.setStore_grade_id(1001); // 店铺等级,默认为普通店铺 shopStoreBase.setStore_type(1);//店铺类型(ENUM): 1-卖家店铺; 2-供应商店铺 shopStoreBase.setStore_is_open(1); @@ -3062,7 +3061,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl - + * From 2ed235f8fb18e18865295cb93609ee9b09ce9705 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 4 May 2025 23:33:26 +0800 Subject: [PATCH 11/39] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=95=86=E8=A1=A8=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/esign/EsignPlatformInfo.java | 3 + .../modules/lakala/LklLedgerMember.java | 4 + .../common/modules/store/ShopMchEntry.java | 5 +- .../service/EsignPlatformInfoService.java | 21 ++- .../impl/EsignPlatformInfoServiceImpl.java | 52 +++++- .../service/LklLedgerMemberService.java | 1 + .../service/LklLedgerReceiverService.java | 32 ++++ .../service/impl/LakalaApiServiceImpl.java | 1 + .../impl/LklLedgerReceiverServiceImpl.java | 156 +++++++++++++++++- .../lakala/service/impl/LklTkServiceImpl.java | 16 +- .../store/service/ShopMchEntryService.java | 9 + .../service/impl/ShopMchEntryServiceImpl.java | 22 +++ 12 files changed, 308 insertions(+), 14 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java index fa0adc35..ea3e155d 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignPlatformInfo.java @@ -47,6 +47,9 @@ public class EsignPlatformInfo implements Serializable { @ApiModelProperty(value = "平台方营业执照公司名称") private String license_company; + @ApiModelProperty(value = "平台方营业执照上的经营内容") + private String license_content; + @ApiModelProperty(value = "代理商的省/市/区,如:广东省/深圳市/福田区") private String license_area; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java index 4617fff7..03188643 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java @@ -47,6 +47,10 @@ public class LklLedgerMember implements Serializable { private String audit_resp; private String remark; private Long mch_id; + private Integer has_esigned; + private Integer has_apply_split; + private Integer has_receiver; + private Integer has_bind_receiver; private String version; private Date created_at; private Date updated_at; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 2489279a..f1e83833 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -114,6 +114,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "入驻商家营业执照图片的存储路径") private String biz_license_image; + @ApiModelProperty(value = "入驻商家营业执照的经营范围") + private String biz_license_content; + @ApiModelProperty(value = "入驻商家的许可证类型:1-许可证;2-特许证件,3-其他证件") private Integer license_type; @@ -122,7 +125,7 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "入驻商家许可证图片的存储路径") private String license_image; - + @ApiModelProperty(value = "商家营业执照有效开始时间") private String biz_license_period_begin; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java index 538e2ae8..fcd69b67 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java @@ -11,6 +11,8 @@ package com.suisung.mall.shop.esign.service; import com.suisung.mall.common.modules.esign.EsignPlatformInfo; import org.springframework.data.util.Pair; +import java.util.List; + /** * 平台方详细信息接口 */ @@ -24,14 +26,29 @@ public interface EsignPlatformInfoService { */ EsignPlatformInfo getDistributorInfoById(Long id); + /** + * 根据ID获取代理商信息 + * + * @param ids + * @return + */ + List getDistributorInfoByIds(Long... ids); + /** * 根据分类和营业执照号获取平台方信息 * - * @param type 分类(必选):类型:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理; + * @param level 分类(必选):类型:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理; * @param licenseNumber 营业执照号码(可选) * @return */ - EsignPlatformInfo getEsignPlatformInfo(Integer type, String licenseNumber); + EsignPlatformInfo getEsignPlatformInfo(Integer level, String licenseNumber); + + /** + * 是否存在平台方的相关记录信息? + * + * @return + */ + EsignPlatformInfo hasPlatformMch(); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java index 07bb5830..4d742b83 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java @@ -33,35 +33,51 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl list = getDistributorInfoByIds(id); + if (CollectionUtil.isEmpty(list)) { + return null; + } + + return list.get(0); + } + + /** + * 根据ID获取代理商信息 + * + * @param ids + * @return + */ + @Override + public List getDistributorInfoByIds(Long... ids) { + if (ids == null || ids.length == 0) { return null; } QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("id", id).gt("type", 0).eq("status", CommonConstant.Enable); + queryWrapper.in("id", ids).eq("status", CommonConstant.Enable); List esignPlatformInfos = list(queryWrapper); if (CollectionUtil.isEmpty(esignPlatformInfos)) { return null; } - return esignPlatformInfos.get(0); + return esignPlatformInfos; } /** * 根据分类和营业执照号获取平台方信息 * - * @param type 分类(可选):类型:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理; + * @param level 分类(可选):类型:0-平台方(只能一条记录);1-一级代理;2-二级代理;3-三级代理;4-四级代理; * @param licenseNumber 营业执照号码(可选) * @return */ @Override - public EsignPlatformInfo getEsignPlatformInfo(Integer type, String licenseNumber) { + public EsignPlatformInfo getEsignPlatformInfo(Integer level, String licenseNumber) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("status", CommonConstant.Enable); - if (!ObjectUtils.isEmpty(type)) { - queryWrapper.eq("type", type); + if (!ObjectUtils.isEmpty(level)) { + queryWrapper.eq("level", level); } else { - queryWrapper.eq("type", 0); + queryWrapper.eq("level", 0); } if (StrUtil.isNotBlank(licenseNumber)) { @@ -76,6 +92,24 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("level", 0).eq("status", CommonConstant.Enable); + + EsignPlatformInfo esignPlatformInfo = getOne(queryWrapper); + if (ObjectUtils.isEmpty(esignPlatformInfo)) { + return null; + } + + return esignPlatformInfo; + } + /** * 获取平台方手机号和营业执照号 * @@ -84,7 +118,7 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl getEsignPlatformMobileAndLicenseNumber() { QueryWrapper queryWrapper = new QueryWrapper(); - queryWrapper.eq("type", 0).select("telephone", "license_number", "legal_person_mobile"); + queryWrapper.eq("level", 0).select("telephone", "license_number", "legal_person_mobile"); List esignPlatformInfos = list(queryWrapper); if (CollectionUtil.isEmpty(esignPlatformInfos)) { return null; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index a7cf5191..29bfbda5 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -53,4 +53,5 @@ public interface LklLedgerMemberService extends IBaseService { * @return */ Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java index f144f367..21075bb7 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java @@ -8,6 +8,7 @@ package com.suisung.mall.shop.lakala.service; +import cn.hutool.json.JSONArray; import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; import com.suisung.mall.core.web.service.IBaseService; @@ -29,6 +30,37 @@ public interface LklLedgerReceiverService extends IBaseService implements LklLedgerReceiverService { + + @Resource + private EsignPlatformInfoService esignPlatformInfoService; + + @Lazy + @Resource + private LakalaApiService lakalaApiService; + /** * 根据接收方编号新增或更新记录 * @@ -52,7 +69,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl 0) { - // update + // 更新记录 record.setId(existsRecordList.get(0).getId()); return updateById(record); } @@ -60,6 +77,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("platform_id", platformId).eq("status", CommonConstant.Enable).orderByAsc("id"); + + List lklLedgerReceivers = list(queryWrapper); + if (CollectionUtil.isEmpty(lklLedgerReceivers)) { + return null; + } + + return lklLedgerReceivers.get(0); + } + + /** + * 通过平台方(代理商) ID 记录信息转成 Lakala 接收方记录 + * 平台方一定要获取,如果有代理商也要获取 + * + * @param platformId + * @return + */ + @Override + public JSONArray buildApplyLedgerReceiverReqParams(Long platformId) { + List ids = new ArrayList<>(); + ids.add(0L); + if (ObjectUtil.isNotEmpty(platformId)) { + ids.add(platformId); + } + List esignPlatformInfoList = esignPlatformInfoService.getDistributorInfoByIds(ids.toArray(new Long[0])); + if (CollectionUtil.isEmpty(esignPlatformInfoList)) { + return null; + } + + JSONArray reqParams = new JSONArray(); + for (EsignPlatformInfo esignPlatformInfo : esignPlatformInfoList) { + JSONObject reqParam = new JSONObject(); + + reqParam.put("receiverName", esignPlatformInfo.getLicense_company()); + reqParam.put("contactMobile", esignPlatformInfo.getLegal_person_mobile()); + + reqParam.put("licenseNo", esignPlatformInfo.getLicense_number()); + reqParam.put("licenseName", esignPlatformInfo.getLicense_company()); + reqParam.put("legalPersonName", esignPlatformInfo.getLegal_person_name()); + reqParam.put("legalPersonCertificateType", "17"); + reqParam.put("legalPersonCertificateNo", esignPlatformInfo.getLegal_person_id_card()); + + reqParam.put("acctNo", esignPlatformInfo.getRec_acc_card_no()); + reqParam.put("acctName", esignPlatformInfo.getRec_acc_bank_name()); + reqParam.put("acctTypeCode", "57"); + reqParam.put("acctCertificateType", "17"); + + reqParam.put("acctCertificateNo", esignPlatformInfo.getLegal_person_id_card()); + reqParam.put("acctOpenBankCode", esignPlatformInfo.getRec_acc_bank_no()); + reqParam.put("acctOpenBankName", esignPlatformInfo.getRec_acc_bank_name()); + reqParam.put("acctClearBankCode", esignPlatformInfo.getRec_acc_clear_bank_no()); + + JSONArray attachList = new JSONArray(); + if (StrUtil.isNotBlank(esignPlatformInfo.getLicense_image())) { + JSONObject BUSINESS_LICENCE = new JSONObject(); + BUSINESS_LICENCE.put("attachType", "BUSINESS_LICENCE").put("attachName", "营业执照") + .put("attachStoreFile", esignPlatformInfo.getLicense_image()); + attachList.add(BUSINESS_LICENCE); + } + + if (StrUtil.isNotBlank(esignPlatformInfo.getLegal_person_id_card_image1())) { + JSONObject FR_ID_CARD_FRONT = new JSONObject(); + FR_ID_CARD_FRONT.put("attachType", "FR_ID_CARD_FRONT").put("attachName", "法人身份证正面") + .put("attachStoreFile", esignPlatformInfo.getLegal_person_id_card_image1()); + attachList.add(FR_ID_CARD_FRONT); + } + + if (StrUtil.isNotBlank(esignPlatformInfo.getLegal_person_id_card_image2())) { + JSONObject FR_ID_CARD_BEHIND = new JSONObject(); + FR_ID_CARD_BEHIND.put("attachType", "FR_ID_CARD_BEHIND").put("attachName", "法人身份证反面") + .put("attachStoreFile", esignPlatformInfo.getLegal_person_id_card_image2()); + attachList.add(FR_ID_CARD_BEHIND); + } + + if (CollectionUtil.isNotEmpty(attachList)) { + reqParam.put("attachList", attachList); + } + } + + return reqParams; + } + + /** + * 内部调用:申请分账接收方 + * + * @param platformId + * @return + */ + @Override + public Boolean innerApplyLedgerReceiver(Long platformId) { + JSONArray buildApplyLedgerReceiverReqParams = buildApplyLedgerReceiverReqParams(platformId); + if (CollectionUtil.isEmpty(buildApplyLedgerReceiverReqParams)) { + return false; + } + + int success = 0; + for (JSONObject reqParam : buildApplyLedgerReceiverReqParams.jsonIter()) { + CommonResult result = lakalaApiService.applyLedgerReceiver(reqParam); + if (result == null || result.getCode() != 200) { + continue; + } + success += 1; + } + + return success > 0; + } + + /** + * @return + */ + @Override + public LklLedgerReceiver hasPlatformMch() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("platform_id", 0).eq("status", CommonConstant.Enable).orderByAsc("id"); + + List lklLedgerReceivers = list(queryWrapper); + if (CollectionUtil.isEmpty(lklLedgerReceivers)) { + return null; + } + + return lklLedgerReceivers.get(0); + } + /** * 根据条件查询记录 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 12bc12b6..329732b6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -20,12 +20,14 @@ import com.suisung.mall.common.utils.RestTemplateHttpUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.common.utils.UploadUtil; import com.suisung.mall.core.web.service.RedisService; +import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; import com.suisung.mall.shop.lakala.utils.LakalaUtil; import com.suisung.mall.shop.store.service.ShopMchEntryService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -71,6 +73,10 @@ public class LklTkServiceImpl { @Resource private ShopMchEntryService shopMchEntryService; + @Lazy + @Resource + private LklLedgerReceiverService lklLedgerReceiverService; + @Autowired private RedisService redisService; @@ -412,7 +418,15 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "500").set("message", "更新商户号失败"); } - // 根据入驻商家的代理商或平台方,顺便新增一个接收方记录 + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); + if (ObjectUtil.isEmpty(shopMchEntry)) { + return new JSONObject().set("code", "500").set("message", "商户入驻信息不存在"); + } + + // 1、发起E签宝合同签署;2、立即给商家申请分账功能权限;3、新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 + + //3 + lklLedgerReceiverService.innerApplyLedgerReceiver(shopMchEntry.getDistributor_id()); return new JSONObject().set("code", "200").set("message", "成功"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index d3374586..fc38cc31 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -108,6 +108,15 @@ public interface ShopMchEntryService { */ ShopMchEntry getShopMerchEntryByCondition(String loginMobile, String bizLicenseNumber, Integer approvalStatus); + + /** + * 根据拉卡拉外部商户号获取有效的商家入驻申请记录 + * + * @param merCupNo + * @return + */ + ShopMchEntry getShopMerchEntryByMerCupNo(String merCupNo); + /** * 根据商家注册的手机号,更新合同签署状态和合同下载地址 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 3c2b385c..b62ca359 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -640,6 +640,28 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mer_cup_no", merCupNo).eq("status", CommonConstant.Enable).orderByAsc("id"); + List recordList = list(queryWrapper); + if (CollectionUtil.isEmpty(recordList)) { + return null; + } + + return recordList.get(0); + } + /** * 根据商家注册的手机号,更新合同签署状态和合同下载地址 * From 8873bff6e5d067e511962a0168b1fc00823a768b Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 6 May 2025 00:25:52 +0800 Subject: [PATCH 12/39] =?UTF-8?q?=E5=85=A5=E9=A9=BB=E8=BF=9E=E8=B5=B7?= =?UTF-8?q?=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../esign/service/EsignContractService.java | 8 ++++ .../impl/EsignContractServiceImpl.java | 39 ++++++++------- .../service/LklLedgerMemberService.java | 11 +++++ .../service/LklLedgerReceiverService.java | 3 +- .../service/impl/LakalaApiServiceImpl.java | 8 +++- .../impl/LklLedgerMemberServiceImpl.java | 47 +++++++++++++++++++ .../impl/LklLedgerReceiverServiceImpl.java | 12 ++++- .../lakala/service/impl/LklTkServiceImpl.java | 12 +++-- 8 files changed, 116 insertions(+), 24 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java index 488f40f7..41b7afe1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java @@ -26,6 +26,14 @@ public interface EsignContractService { */ CommonResult signFlowCreateByFile(String mchMobile); + /** + * 内部调用:发起合同签署流程 + * + * @param mchMobile + * @return + */ + Pair innerSignFlowCreateByFile(String mchMobile); + /** * 签署流程结束异步通知(由e签宝通知) * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index 8f585b7b..cbdebd77 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -159,28 +159,32 @@ public class EsignContractServiceImpl extends BaseServiceImpl ret = innerSignFlowCreateByFile(mchMobile); + if (!ret.getFirst()) { + return CommonResult.failed(ret.getSecond()); + } -// UserDto user = getCurrentUser(); -// if (!user.isAdmin()) { -// return CommonResult.failed("权限不足!"); -// } -// userId = user.getId().toString(); + return CommonResult.success(null, ret.getSecond()); + } + + @Override + public Pair innerSignFlowCreateByFile(String mchMobile) { + //String userId = "0"; if (StrUtil.isBlank(mchMobile)) { - return CommonResult.failed("缺少必要参数!"); + return Pair.of(false, "缺少必要参数!"); } EsignContract esignContract = getEsignContractByMchMobile(mchMobile); if (esignContract == null) { - return CommonResult.failed("未找到商家合同信息"); + return Pair.of(false, "未找到商家合同信息"); } // 检查商户入驻信息是否被审核通过 // 检查店铺是否已经申请过入驻 Integer apprStatus = shopMchEntryService.getApprovalStatus(mchMobile); if (!CommonConstant.MCH_APPR_STA_PASS.equals(apprStatus)) { - return CommonResult.failed("请先审核商家入驻信息"); + return Pair.of(false, "请先审核商家入驻信息"); } //"{\"docs\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"fileName\":\"平台商户入驻合同协议.pdf\"}],\"signFlowConfig\":{\"signFlowTitle\":\"平台商户入驻合同协议\",\"signFlowExpireTime\":1746844718000,\"autoFinish\":true,\"notifyUrl\":\"https://mall.gpxscs.cn/asyn/notify\",\"redirectConfig\":{\"redirectUrl\":\"https://mall.gpxscs.cn/\"}},\"signers\":[{\"signConfig\":{\"signOrder\":1},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":0,\"psnSignerInfo\":{\"psnAccount\":\"13128997057\",\"psnInfo\":{\"psnName\":\"潘军杰\"}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":40,\"positionX\":472.3607,\"positionY\":277.19104}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":470.58798,\"positionY\":589.14496}}}]},{\"signConfig\":{\"signOrder\":2},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":1,\"orgSignerInfo\":{\"orgName\":\"桂平发发网络有限公司\",\"orgInfo\":{\"orgIDCardNum\":\"91450881MADEQ92533\",\"orgIDCardType\":\"CRED_ORG_USCC\"},\"transactorInfo\":{\"psnAccount\":\"17777525395\",\"psnInfo\":{\"psnName\":\"谢能坤\"}}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":2,\"positionX\":479.04996,\"positionY\":357.2327}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":255.96832,\"positionY\":588.4553}}}]}]}"; @@ -198,7 +202,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl { + taskService.executeTask(() -> { + // 申请分账 + + // 新建一个正式的已审核通过的店铺 Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); if (retPair.getFirst() > 0) { // 更改合同记录表的店铺id diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index 29bfbda5..566090cf 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -54,4 +54,15 @@ public interface LklLedgerMemberService extends IBaseService { */ Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark); + /** + * 更新分账多个状态 + * + * @param merCupNo + * @param hasEsigned + * @param hasApplySplit + * @param hasReceiver + * @param hasBindReceiver + * @return + */ + Boolean updateMulStatus(String merCupNo, Integer hasEsigned, Integer hasApplySplit, Integer hasReceiver, Integer hasBindReceiver); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java index 21075bb7..ec56d015 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java @@ -49,10 +49,11 @@ public interface LklLedgerReceiverService extends IBaseService updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("mer_cup_no", merCupNo); + if (hasEsigned != null && hasEsigned > 0) { + i++; + updateWrapper.set("has_esigned", hasEsigned); + } + if (hasApplySplit != null && hasApplySplit > 0) { + i++; + updateWrapper.set("has_apply_split", hasApplySplit); + } + if (hasReceiver != null && hasReceiver > 0) { + i++; + updateWrapper.set("has_receiver", hasReceiver); + } + if (hasBindReceiver != null && hasBindReceiver > 0) { + i++; + updateWrapper.set("has_bind_receiver", hasBindReceiver); + } + + if (i == 0) { + return false; + } + + return update(updateWrapper); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 518a981b..e3b329b3 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -22,6 +22,7 @@ import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; import com.suisung.mall.shop.lakala.mapper.LklLedgerReceiverMapper; import com.suisung.mall.shop.lakala.service.LakalaApiService; +import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -40,6 +41,10 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl Date: Thu, 8 May 2025 00:35:12 +0800 Subject: [PATCH 13/39] =?UTF-8?q?ocr=20=E8=B0=83=E8=AF=95=EF=BC=8Ctodo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/mobile/WeiXinController.java | 8 +- .../mall/account/service/WeiXinService.java | 8 ++ .../service/impl/WeiXinServiceImpl.java | 9 +- .../oss/service/impl/OssServiceImpl.java | 51 ++++--- .../impl/EsignContractServiceImpl.java | 2 +- .../controller/mobile/LklTkController.java | 18 ++- .../shop/lakala/service/LakalaApiService.java | 11 ++ .../service/impl/LakalaApiServiceImpl.java | 8 ++ .../lakala/service/impl/LklTkServiceImpl.java | 134 +++++++++++++++--- .../page/service/impl/OssServiceImpl.java | 3 +- .../impl/ShopStoreMediaServiceImpl.java | 6 +- 11 files changed, 204 insertions(+), 54 deletions(-) diff --git a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java index adaf468a..21715055 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java +++ b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java @@ -84,8 +84,14 @@ public class WeiXinController extends BaseControllerImpl { return CommonResult.success(weiXinService.jsCode2Session(code, encryptedData, iv, activity_id, user_info)); } + @ApiOperation(value = "获取微信的 OpenId") + @RequestMapping(value = "/getWxOpenId", method = {RequestMethod.GET, RequestMethod.POST}) + public CommonResult jsCode2Session(@RequestParam(name = "code") String code) { + return CommonResult.success(weiXinService.getJsCode2Session(code)); + } + @ApiOperation(value = "获取微信小程序用户授权手机号,并绑定登录用户") - @RequestMapping(value = "/getUserPhoneNumber", method = RequestMethod.GET) + @RequestMapping(value = "/getUserPhoneNumber", method = {RequestMethod.GET, RequestMethod.POST}) public CommonResult getUserPhoneNumber(@RequestParam(name = "code") String code) { return CommonResult.success(weiXinService.getUserPhoneNumberAndBindUser(code, getCurrentUser())); } diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/WeiXinService.java b/mall-account/src/main/java/com/suisung/mall/account/service/WeiXinService.java index 581f4faf..c81aadaa 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/service/WeiXinService.java +++ b/mall-account/src/main/java/com/suisung/mall/account/service/WeiXinService.java @@ -35,6 +35,14 @@ public interface WeiXinService { Map checkAppLogin(String code); + /** + * 纯粹获取微信用户的 OpenId + * + * @param code + * @return + */ + Map getJsCode2Session(String code); + Map jsCode2Session(String code, String encryptedData, String iv, String activity_id, String user_info); /** diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/impl/WeiXinServiceImpl.java b/mall-account/src/main/java/com/suisung/mall/account/service/impl/WeiXinServiceImpl.java index 6d679c9d..4cf67f78 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/service/impl/WeiXinServiceImpl.java +++ b/mall-account/src/main/java/com/suisung/mall/account/service/impl/WeiXinServiceImpl.java @@ -359,7 +359,14 @@ public class WeiXinServiceImpl implements WeiXinService { return userInfo; } - private Map getJsCode2Session(String code) { + /** + * 纯粹获取微信用户的 OpenId + * + * @param code + * @return + */ + @Override + public Map getJsCode2Session(String code) { //从微信服务器获得session_key,openid,unionid String url = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code"; diff --git a/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java b/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java index a7fa5262..96a35ed2 100644 --- a/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java +++ b/mall-admin/src/main/java/com/suisung/mall/admin/oss/service/impl/OssServiceImpl.java @@ -41,6 +41,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.*; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; @@ -92,6 +93,18 @@ public class OssServiceImpl implements OssService { @Value("${upload.filepath}") private String FILEPATH; + /** + * 判断路径是否存在,不存在创建 + * + * @param dirPath + */ + private static void isChartPathExist(String dirPath) { + File file = new File(dirPath); + if (!file.exists()) { + file.mkdirs(); + } + } + /** * 移动端上传文件 * @@ -163,7 +176,7 @@ public class OssServiceImpl implements OssService { if (uploadType.equals(1)) { url = ConfigConstant.URL_BASE + "/admin/oss/upload/" + dir + "/" + uploadName; // 文件本地路径 - } else if (uploadType.equals(2)){ + } else if (uploadType.equals(2)) { // oss 服务 try { url = uploadObject2OSS(new File(uploadPath), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(uploadName)); @@ -186,13 +199,11 @@ public class OssServiceImpl implements OssService { //截图 //todo 放入upload中 String thumb_file_url = ""; - if (VideoUtil.videoAllowFiles.contains(VideoUtil.getVideoFormat(uploadPath))) - { + if (VideoUtil.videoAllowFiles.contains(VideoUtil.getVideoFormat(uploadPath))) { String cover_path = uploadPath.replace("." + VideoUtil.getVideoFormat(uploadPath), ".jpg"); String cover_upname = uploadName.replace("." + VideoUtil.getVideoFormat(uploadName), ".jpg"); - if (VideoUtil.getVideoCover(uploadPath, cover_path, 1, "375*667")) - { + if (VideoUtil.getVideoCover(uploadPath, cover_path, 1, "375*667")) { try { thumb_file_url = uploadObject2OSS(new File(cover_path), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/").concat(cover_upname)); } catch (Exception e) { @@ -200,9 +211,7 @@ public class OssServiceImpl implements OssService { thumb_file_url = ""; } - } - else - { + } else { thumb_file_url = ""; } } @@ -247,7 +256,7 @@ public class OssServiceImpl implements OssService { // 创建唯一文件名称 String suffix = fileName.substring(fileName.lastIndexOf(".")); String uploadName = IdUtil.simpleUUID() + suffix; - String uploadPath = FILEPATH + "/" + dir + "/" + uploadName; + String uploadPath = FILEPATH + "/" + dir + "/" + uploadName; String imageAllowExt = configService.getConfig("image_allow_ext", ""); String[] imageAllowExtList = imageAllowExt.split(","); @@ -297,9 +306,9 @@ public class OssServiceImpl implements OssService { } } - /** * 腾讯云上传 + * * @param file * @param concat * @return @@ -378,10 +387,10 @@ public class OssServiceImpl implements OssService { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String dir = ALIYUN_OSS_DIR_PREFIX + sdf.format(new Date()); // 签名有效期 - long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000; + long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000L; Date expiration = new Date(expireEndTime); // 文件大小 - long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024; + long maxSize = (long) ALIYUN_OSS_MAX_SIZE * 1024 * 1024; // 回调 OssCallbackParamDTO callback = new OssCallbackParamDTO(); callback.setCallbackUrl(ALIYUN_OSS_CALLBACK); @@ -394,10 +403,10 @@ public class OssServiceImpl implements OssService { policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize); policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); - byte[] binaryData = postPolicy.getBytes("utf-8"); + byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); String policy = BinaryUtil.toBase64String(binaryData); String signature = ossClient.calculatePostSignature(postPolicy); - String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8")); + String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes(StandardCharsets.UTF_8)); // 返回结果 result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId()); result.setPolicy(policy); @@ -486,7 +495,7 @@ public class OssServiceImpl implements OssService { * @return */ private String getUserDirName(UserDto user) { - if (user.getId() == null) { + if (user == null || user.getId() == null) { throw new ApiException(I18nUtil._("获取用户信息失败!")); } if (user.isPlatform()) { @@ -499,16 +508,4 @@ public class OssServiceImpl implements OssService { } } } - - /** - * 判断路径是否存在,不存在创建 - * - * @param dirPath - */ - private static void isChartPathExist(String dirPath) { - File file = new File(dirPath); - if (!file.exists()) { - file.mkdirs(); - } - } } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index cbdebd77..5dfa1e1b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -295,7 +295,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl { - // 申请分账 + // 1、(电子合同)给商家申请分账功能;2、商家绑定接收方; // 新建一个正式的已审核通过的店铺 Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index 6f39485f..39e8cb7c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -9,6 +9,7 @@ package com.suisung.mall.shop.lakala.controller.mobile; import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import io.swagger.annotations.Api; @@ -17,7 +18,9 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -44,9 +47,18 @@ public class LklTkController extends BaseControllerImpl { } @ApiOperation(value = "上传文件", notes = "上传文件") - @RequestMapping(value = "/uploadWithOCR", method = {RequestMethod.POST, RequestMethod.GET}) - public JSONObject uploadWithOCR(String fileURL) { - return lklTkService.uploadFileWithOcr("", fileURL, "ID_CARD_FRONT"); + @RequestMapping(value = "/uploadOcrImg", method = RequestMethod.POST) + public CommonResult uploadOcrImg(@RequestParam(name = "upfile") MultipartFile file, + @RequestParam(name = "imgType") String imgType) { + + return lklTkService.uploadOcrImg(file, imgType); + } + + @ApiOperation(value = "获取(身份证、营业执照、身份证)图片的信息", notes = "获取(身份证、营业执照、身份证)图片的信息") + @RequestMapping(value = "/imgOcrResult", method = RequestMethod.POST) + public CommonResult imgOcrResult(@RequestParam(name = "batchNo") String batchNo, + @RequestParam(name = "imgType") String imgType) { + return lklTkService.imgOcrResult(batchNo, imgType); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index b5334ce4..5f20588f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -14,6 +14,9 @@ import com.suisung.mall.common.api.CommonResult; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +/** + * 拉卡拉业务接口 + */ public interface LakalaApiService { Boolean initLKLSDK(); @@ -143,5 +146,13 @@ public interface LakalaApiService { */ JSONObject getBankCardBin(String bankCardNo); + /** + * @param imgURL + * @param imgType 法人身份证正面图:FR_ID_CARD_FRONT;法人身份证反面:FR_ID_CARD_BEHIND; + * 身份证正面:ID_CARD_FRONT;身份证反面:ID_CARD_BEHIND; + * 营业执照:BUSINESS_LICENSE;银行卡:BANK_CARD + * @return + */ + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index c22ab1db..af91a5bc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -556,6 +556,10 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retCode", lklSuccessCode); respData.put("retMsg", "操作成功!"); log.info("商户分账申请业务回调:处理成功"); + + // TODO 绑定接收方(平台方和代理商),绑定之前,判断是否已经绑定过了? + + } } @@ -753,6 +757,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { LklLedgerMerReceiverBind lklLedgerMerReceiverBind = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMerReceiverBind.class); lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(lklLedgerMerReceiverBind); + return CommonResult.success(lklLedgerMerReceiverBind, "提交成功,待审核中!"); } catch (SDKException e) { log.error("分账绑定关系申请失败:", e); @@ -797,6 +802,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { paramsJSON.getStr("remark")); if (success) { respData.put("retCode", lklSuccessCode); + + // TODO 新建一个正式的已审核通过的店铺, 新建之前判断是否已经新建过了? + respData.put("retMsg", "操作成功!"); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 963a6e12..8a96559f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -14,7 +14,10 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.api.ResultCode; import com.suisung.mall.common.constant.CommonConstant; +import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.utils.RestTemplateHttpUtil; import com.suisung.mall.common.utils.StringUtils; @@ -23,6 +26,7 @@ import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; import com.suisung.mall.shop.lakala.utils.LakalaUtil; +import com.suisung.mall.shop.page.service.impl.OssServiceImpl; import com.suisung.mall.shop.store.service.ShopMchEntryService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +37,7 @@ import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.crypto.Cipher; @@ -46,6 +51,8 @@ import java.util.Base64; import java.util.HashMap; import java.util.Map; +import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; + @Service public class LklTkServiceImpl { @@ -82,6 +89,10 @@ public class LklTkServiceImpl { @Resource private EsignContractService esignContractService; + @Lazy + @Resource + private OssServiceImpl ossService; + @Autowired private RedisService redisService; @@ -135,26 +146,49 @@ public class LklTkServiceImpl { /** * 上传文件(图片)到拉卡拉,带 OCR识别卡信息,身份证信息,营业执照信息 * - * @param fileBase64 图片的base64字符串 - * @param fileURL 图片的url地址 - * @param imgType 图片类型 + * @param file 图片URL地址 + * @param imgType 法人身份证正面图:FR_ID_CARD_FRONT; + * 法人身份证反面:FR_ID_CARD_BEHIND; + * 身份证正面:ID_CARD_FRONT; + * 身份证反面:ID_CARD_BEHIND; + * 营业执照:BUSINESS_LICENCE; + * 银行卡:BANK_CARD * @return */ - public JSONObject uploadFileWithOcr(String fileBase64, String fileURL, String imgType) { + public CommonResult uploadOcrImg(MultipartFile file, String imgType) { + + if (file == null || StrUtil.isBlank(imgType)) { + return CommonResult.failed("上传文件或图片类型不能为空"); + } + + UserDto user = getCurrentUser(); + if (user == null) { + return CommonResult.failed("请先登录"); + } + + CommonResult ossImgInfo = ossService.uploadFile(file, user); + if (ossImgInfo == null) { + return CommonResult.failed("上传文件失败"); + } + + if (ossImgInfo.getStatus() != ResultCode.SUCCESS.getStatus() || ossImgInfo.getData() == null) { + return CommonResult.failed(ossImgInfo.getMsg()); + } + + String imgURL = JSONUtil.parseObj(ossImgInfo.getData()).getStr("url"); + String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { - return JSONUtil.createObj().set("code", 500).set("msg", "获取拉卡拉token失败"); + return CommonResult.failed("获取拉卡拉token失败"); } JSONObject header = new JSONObject(); header.put("Authorization", authorization); - String urlPath = isProd() ? "/registration/file/upload" : "/sit/htkregistration/file/upload"; - if (StrUtil.isBlank(fileBase64)) { - // web url 转 base64 字节 - fileBase64 = UploadUtil.URLFileToBase64(fileURL); - } + String updUrlPath = isProd() ? "/registration/file/base/upload" : "/sit/htkregistration/file/base/upload"; + String fileBase64 = UploadUtil.URLFileToBase64(imgURL); + JSONObject requestBody = new JSONObject(); requestBody.put("fileBase64", fileBase64); @@ -162,15 +196,82 @@ public class LklTkServiceImpl { requestBody.put("sourcechnl", "0"); // 来源: 0:PC,1:安卓,2:IOS requestBody.put("isOcr", "true"); - ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklServiceUrl(urlPath), header, requestBody, JSONObject.class); - if (ObjectUtil.isEmpty(response) - || response.getStatusCode() != HttpStatus.OK - || ObjectUtil.isEmpty(response.getBody())) { - return JSONUtil.createObj().set("code", 500).set("msg", "返回值有误!"); + ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); + if (ObjectUtil.isEmpty(updResponse) + || updResponse.getStatusCode() != HttpStatus.OK + || ObjectUtil.isEmpty(updResponse.getBody())) { + return CommonResult.failed("上传文件返回值有误"); } // {batchNo,status,url,showUrl,result{} } - return response.getBody(); + JSONObject updObj = updResponse.getBody(); + String batchNo = updObj.getStr("batchNo"); + if (StrUtil.isBlank(batchNo)) { + return CommonResult.failed("上传文件返回值有误"); + } + + updObj.put("url", imgURL); + + // 调用 OCR 识别接口 +// String ocrUrlPath = isProd() ? "/registration/ocr/result" : "/sit/htkregistration/ocr/result"; +// JSONObject ocrRequestBody = new JSONObject(); +// ocrRequestBody.put("batchNo", batchNo); +// ocrRequestBody.put("imgType", imgType); +// +// ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); +// if (ObjectUtil.isEmpty(ocrResponse) +// || ocrResponse.getStatusCode() != HttpStatus.OK +// || ObjectUtil.isEmpty(ocrResponse.getBody())) { +// return CommonResult.failed("OCR响应数据有误"); +// } +// +// +// JSONObject ocrObj = ocrResponse.getBody().get("result", JSONObject.class); +// if (ObjectUtil.isEmpty(ocrObj)) { +// return CommonResult.failed("OCR返回结果有误"); +// } +// +// ocrObj.put("url", updObj.getStr("url")); +// ocrObj.put("showUrl", updObj.getStr("showUrl")); +// ocrObj.put("imgType", imgType); +// ocrObj.put("batchNo", batchNo); + + return CommonResult.success(updObj); + + } + + public CommonResult imgOcrResult(String batchNo, String imgType) { + + // 调用 OCR 识别接口 + String authorization = getLklTkAuthorization(); + if (StrUtil.isBlank(authorization)) { + return CommonResult.failed("获取拉卡拉token失败"); + } + + JSONObject header = new JSONObject(); + header.put("Authorization", authorization); + + String ocrUrlPath = isProd() ? "/registration/ocr/result" : "/sit/htkregistration/ocr/result"; + JSONObject ocrRequestBody = new JSONObject(); + ocrRequestBody.put("batchNo", batchNo); + ocrRequestBody.put("imgType", imgType); + + ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); + if (ObjectUtil.isEmpty(ocrResponse) + || ocrResponse.getStatusCode() != HttpStatus.OK + || ObjectUtil.isEmpty(ocrResponse.getBody())) { + return CommonResult.failed("OCR响应数据有误"); + } + + + JSONObject ocrObj = ocrResponse.getBody().get("result", JSONObject.class); + if (ObjectUtil.isEmpty(ocrObj)) { + return CommonResult.failed("OCR返回结果有误"); + } + + + return CommonResult.success(ocrObj); + } /** @@ -563,4 +664,5 @@ public class LklTkServiceImpl { return jsonObject; } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java index 541ee80d..3199fbde 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java @@ -553,8 +553,9 @@ public class OssServiceImpl implements OssService { * @return */ private String getUserDirName(UserDto user) { - if (user.getId() == null) { + if (user == null || user.getId() == null) { //throw new ApiException(I18nUtil._("获取用户信息失败!")); + logger.error("cos 文件上传,获取用户信息失败!"); return "media/plantform/default/"; } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreMediaServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreMediaServiceImpl.java index 168ba534..13affa8a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreMediaServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreMediaServiceImpl.java @@ -66,7 +66,7 @@ public class ShopStoreMediaServiceImpl extends BaseServiceImpl Date: Thu, 8 May 2025 11:50:39 +0800 Subject: [PATCH 14/39] =?UTF-8?q?ocr=20=E8=B0=83=E8=AF=95=EF=BC=8Ctodo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suisung/mall/common/utils/UploadUtil.java | 48 ++++++++++++++----- .../impl/EsignContractServiceImpl.java | 26 +++++----- .../service/impl/LakalaApiServiceImpl.java | 48 +++++++++++++++++-- .../impl/LklLedgerReceiverServiceImpl.java | 2 + .../lakala/service/impl/LklTkServiceImpl.java | 16 +++++-- 5 files changed, 105 insertions(+), 35 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java index 408caef2..cf21cbbf 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.apache.tika.Tika; import org.springframework.util.Base64Utils; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -30,7 +31,7 @@ public class UploadUtil { ); public static void main(String[] args) { - String base64 = URLFileToBase64("http://gips3.baidu.com/it/u=1022347589,1106887837&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280"); + String base64 = fileUrlToBase64("http://gips3.baidu.com/it/u=1022347589,1106887837&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280"); System.out.println(base64); } @@ -281,25 +282,46 @@ public class UploadUtil { * @param fileUrl * @return */ - public static String URLFileToBase64(String fileUrl) { + public static String fileUrlToBase64(String fileUrl) { try { URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); - try (InputStream inputStream = connection.getInputStream()) { - byte[] buffer = new byte[inputStream.available()]; - inputStream.read(buffer); - return Base64Utils.encodeToString(buffer); - } finally { - connection.disconnect(); + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + InputStream inputStream = connection.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + byte[] imageBytes = outputStream.toByteArray(); + inputStream.close(); + outputStream.close(); + + return Base64Utils.encodeToString(imageBytes); } - } catch (MalformedURLException e) { - log.error("输入的 URL 格式不正确: {}", e.getMessage()); } catch (IOException e) { - log.error("在连接或读取文件时发生 I/O 错误: {}", e.getMessage()); - } catch (Exception e) { - log.error("发生未知异常: {}", e.getMessage()); + // 可以在这里添加日志记录,方便调试,这里简单打印异常信息 + log.error("处理图片 URL 时出现 IOException: ", e.getMessage()); + } + return null; + } + + /** + * 将MultipartFile 图片转换为Base64字符串 + * + * @param multipartFile + * @return + */ + public static String multipartFileToBase64(MultipartFile multipartFile) { + try { + return Base64Utils.encodeToString(multipartFile.getBytes()); + } catch (IOException e) { + // 可以在这里添加日志记录,方便调试,这里简单打印异常信息 + log.error("处理图片 URL 时出现 IOException: ", e.getMessage()); } return null; } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index 5dfa1e1b..28650b90 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -294,21 +294,21 @@ public class EsignContractServiceImpl extends BaseServiceImpl { - // 1、(电子合同)给商家申请分账功能;2、商家绑定接收方; + // taskService.executeTask(() -> { + // 1、(电子合同)给商家申请分账功能;2、商家绑定接收方; - // 新建一个正式的已审核通过的店铺 - Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); - if (retPair.getFirst() > 0) { - // 更改合同记录表的店铺id - updateContractStoreId(esignContract.getMch_mobile(), retPair.getFirst()); - // 填充合同模版表的店铺Id - esignContractFillingFileService.updateContractFillingStoreId(esignContract.getMch_mobile(), retPair.getFirst()); - // 店铺创建状态已完成 - shopMchEntryService.updateMerchEntryStoreStatus(esignContract.getMch_mobile(), CommonConstant.Enable); - } + // 新建一个正式的已审核通过的店铺 +// Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); +// if (retPair.getFirst() > 0) { +// // 更改合同记录表的店铺id +// updateContractStoreId(esignContract.getMch_mobile(), retPair.getFirst()); +// // 填充合同模版表的店铺Id +// esignContractFillingFileService.updateContractFillingStoreId(esignContract.getMch_mobile(), retPair.getFirst()); +// // 店铺创建状态已完成 +// shopMchEntryService.updateMerchEntryStoreStatus(esignContract.getMch_mobile(), CommonConstant.Enable); +// } - }); + // }); return new ResponseEntity<>(new JSONObject().put("code", 200).put("msg", "success").toString(), HttpStatus.OK); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index af91a5bc..d8221166 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -26,21 +26,28 @@ import com.suisung.mall.common.feignService.ShopService; import com.suisung.mall.common.modules.lakala.LklLedgerMember; import com.suisung.mall.common.modules.lakala.LklLedgerMerReceiverBind; import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; +import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.modules.store.ShopStoreBase; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.common.utils.UploadUtil; +import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; +import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.lakala.service.LakalaApiService; import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; import com.suisung.mall.shop.lakala.service.LklLedgerMerReceiverBindService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; import com.suisung.mall.shop.lakala.utils.LakalaUtil; +import com.suisung.mall.shop.store.service.ShopMchEntryService; +import com.suisung.mall.shop.store.service.ShopStoreBaseService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; @@ -92,6 +99,24 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Autowired private LklLedgerMerReceiverBindService lklLedgerMerReceiverBindService; + @Lazy + @Resource + private ShopMchEntryService shopMchEntryService; + + @Lazy + @Resource + private + EsignContractService esignContractService; + + @Lazy + @Resource + private EsignContractFillingFileService esignContractFillingFileService; + + + @Lazy + @Resource + private ShopStoreBaseService shopStoreBaseService; + /** * 初始化 拉卡拉SDK * @@ -447,7 +472,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setSplitEntrustFileName(fileName); // 分账结算委托书文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.URLFileToBase64(paramsJSON.getStr("splitEntrustFile"))); + JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(paramsJSON.getStr("splitEntrustFile"))); if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); } @@ -617,7 +642,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { for (JSONObject attachJSON : paramsJSON.getJSONArray("attachList").jsonIter()) { String fileName = attachJSON.getStr("attachName"); String attachType = attachJSON.getStr("attachType"); - String fileBase64 = UploadUtil.URLFileToBase64(attachJSON.getStr("attachStoreFile")); // 这个是 url 地址,不是 base64 字节码 + String fileBase64 = UploadUtil.fileUrlToBase64(attachJSON.getStr("attachStoreFile")); // 这个是 url 地址,不是 base64 字节码 attachInfo.setAttachName(fileName); attachInfo.setAttachType(attachType); @@ -710,7 +735,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setReceiverNo(paramsJSON.getStr("receiverNo")); String fileName = paramsJSON.getStr("entrustFileName"); - String splitEntrustFileBase64 = UploadUtil.URLFileToBase64(paramsJSON.getStr("entrustFile")); // 这个是 url 地址,不是 base64 字节码 + String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(paramsJSON.getStr("entrustFile")); // 这个是 url 地址,不是 base64 字节码 req.setEntrustFileName(fileName); String domain = projectDomain; @@ -791,9 +816,10 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retMsg", "响应处理失败!"); if (paramsJSON != null) { + String merCupNo = paramsJSON.getStr("merCupNo"); Boolean success = lklLedgerMerReceiverBindService.updateAuditResult(paramsJSON.getStr("applyId"), paramsJSON.getStr("merInnerNo"), - paramsJSON.getStr("merCupNo"), + merCupNo, paramsJSON.getStr("receiverNo"), paramsJSON.getStr("entrustFileName"), paramsJSON.getStr("entrustFilePath"), @@ -804,6 +830,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retCode", lklSuccessCode); // TODO 新建一个正式的已审核通过的店铺, 新建之前判断是否已经新建过了? + // 新建一个正式的已审核通过的店铺 + ShopMchEntry shopEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); + if (shopEntry != null) { + String mchMobile = shopEntry.getLogin_mobile(); + Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(mchMobile); + if (retPair.getFirst() > 0) { + // 更改合同记录表的店铺id + esignContractService.updateContractStoreId(mchMobile, retPair.getFirst()); + // 填充合同模版表的店铺Id + esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); + // 店铺创建状态已完成 + shopMchEntryService.updateMerchEntryStoreStatus(mchMobile, CommonConstant.Enable); + } + } respData.put("retMsg", "操作成功!"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index e3b329b3..1814594b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -226,6 +226,8 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl Date: Fri, 9 May 2025 00:30:19 +0800 Subject: [PATCH 15/39] =?UTF-8?q?ocr=20=E8=B0=83=E8=AF=95=EF=BC=8Ctodo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/store/ShopMchEntry.java | 5 +- .../mall/common/utils/ContextUtil.java | 2 +- .../impl/EsignContractServiceImpl.java | 13 +- .../controller/mobile/LakalaController.java | 1 + .../shop/lakala/service/LakalaApiService.java | 9 + .../service/LklLedgerReceiverService.java | 11 + .../service/impl/LakalaApiServiceImpl.java | 262 +++++++++++++++++- .../impl/LklLedgerReceiverServiceImpl.java | 20 ++ .../lakala/service/impl/LklTkServiceImpl.java | 20 +- .../src/main/resources/bootstrap-prod.yml | 2 +- 10 files changed, 324 insertions(+), 21 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index f1e83833..3128033a 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -125,7 +125,7 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "入驻商家许可证图片的存储路径") private String license_image; - + @ApiModelProperty(value = "商家营业执照有效开始时间") private String biz_license_period_begin; @@ -216,6 +216,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "商家的代理商ID") private Long distributor_id; + @ApiModelProperty(value = "拉卡拉内部商户号") + private String lkl_mer_inner_no; + @ApiModelProperty(value = "拉卡拉银联商户号(唯一)") private String lkl_mer_cup_no; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java index 86c78c82..60ac8005 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java @@ -39,7 +39,7 @@ public class ContextUtil { public static UserDto getCurrentUser() { try { UserDto loginUser = staticUserInfoService.getUser(); - log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser)); + // log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser)); return loginUser; } catch (Exception e) { System.out.println(e.getMessage()); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index 28650b90..9cf8d63b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -32,6 +32,7 @@ import com.suisung.mall.shop.esign.utils.comm.EsignHttpHelper; import com.suisung.mall.shop.esign.utils.comm.EsignHttpResponse; import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import com.suisung.mall.shop.lakala.service.LakalaApiService; import com.suisung.mall.shop.page.service.OssService; import com.suisung.mall.shop.store.service.ShopMchEntryService; import com.suisung.mall.shop.store.service.ShopStoreBaseService; @@ -92,6 +93,10 @@ public class EsignContractServiceImpl extends BaseServiceImpl retPair = lakalaApiService.innerApplyLedgerMer(esignContract.getMch_mobile()); + if (!retPair.getFirst()) { + log.error("商家申请分账功能失败:{}", retPair.getSecond()); + } + // taskService.executeTask(() -> { - // 1、(电子合同)给商家申请分账功能;2、商家绑定接收方; + // 1、(电子合同)给商家申请分账功能使用; // 新建一个正式的已审核通过的店铺 // Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 106a1785..871c08f4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -49,6 +49,7 @@ public class LakalaController extends BaseControllerImpl { return lakalaPayService.applyLedgerMer(paramsJSON); } + @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调") @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 5f20588f..3c7fc470 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -10,6 +10,7 @@ package com.suisung.mall.shop.lakala.service; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; +import org.springframework.data.util.Pair; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -99,6 +100,14 @@ public interface LakalaApiService { */ CommonResult applyLedgerMer(JSONObject paramsJSON); + /** + * 内部调用:商户分账业务开通申请 + * + * @param merCupNo + * @return + */ + Pair innerApplyLedgerMer(String merCupNo); + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java index ec56d015..26886a3a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerReceiverService.java @@ -12,6 +12,8 @@ import cn.hutool.json.JSONArray; import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; import com.suisung.mall.core.web.service.IBaseService; +import java.util.List; + public interface LklLedgerReceiverService extends IBaseService { /** @@ -71,4 +73,13 @@ public interface LklLedgerReceiverService extends IBaseService getByCondition(String LicenseNo, String ContactMobile); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index d8221166..a7199955 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -46,6 +46,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -449,6 +450,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { } + /** + * 商户分账业务开通申请 + * + * @param paramsJSON + * @return + */ @Override public CommonResult applyLedgerMer(JSONObject paramsJSON) { log.info("商户分账业务开通申请开始"); @@ -462,9 +469,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setVersion("2.0"); req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 req.setOrgCode(orgCode); - req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); - req.setMerCupNo(paramsJSON.getStr("merCupNo")); - req.setContactMobile(paramsJSON.getStr("contactMobile")); + req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));// 从进件申请返回的商户号 + req.setMerCupNo(paramsJSON.getStr("merCupNo")); // 从进件申请返回的商户号 + req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) req.setSplitLowestRatio(BigDecimal.valueOf(70)); @@ -512,6 +519,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); paramsJSON.set("audit_status_text", paramsJSON.get("remark")); + paramsJSON.set("mch_id", paramsJSON.get("mchId")); + // 新增数据 // 将 JSON 对象的键名转换为下划线命名 LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); @@ -520,7 +529,112 @@ public class LakalaApiServiceImpl implements LakalaApiService { return CommonResult.success(null, "提交成功,待审核中!"); } catch (SDKException e) { log.error("申请开通分账出错:", e); - throw new ApiException(I18nUtil._("申请开通分账出错!"), e); + throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); + } + } + + @Override + public Pair innerApplyLedgerMer(String merCupNo) { + log.info("商户分账业务开通申请开始"); + + if (StringUtils.isBlank(merCupNo)) { + return Pair.of(false, I18nUtil._("商户号不能为空!")); + } + + // 获取商户入驻记录 + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); + if (shopMchEntry == null) { + return Pair.of(false, I18nUtil._("商家入驻信息不存在!")); + } + + // 判断是否已经申请过? + LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo); + if (lklLedgerMember != null) { + return Pair.of(true, I18nUtil._("商家已经申请过了!")); + } + + + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); + req.setVersion("2.0"); + req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 + req.setOrgCode(orgCode); + req.setMerInnerNo(shopMchEntry.getLkl_mer_inner_no());// 从进件申请返回的商户号 + req.setMerCupNo(shopMchEntry.getLkl_mer_cup_no()); // 从进件申请返回的商户号 + req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 + // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 + // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) + req.setSplitLowestRatio(BigDecimal.valueOf(70)); + String fileName = "小发同城分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); + req.setSplitEntrustFileName(fileName); + + // 分账结算委托书文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(shopMchEntry.getContract_download_url())); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + throw new ApiException(I18nUtil._("小发同城分账授权委托书上传失败!")); + } + + String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); + req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + + String domain = projectDomain; + if (isProd()) { + domain += "/api"; + } + // 给拉卡拉通知的回调地址 + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; + req.setRetUrl(retUrl); + + JSONObject paramsJSON = new JSONObject(); + paramsJSON.put("orderNo", req.getOrderNo()); + paramsJSON.put("org_code", orgCode); + paramsJSON.put("version", "2.0"); + paramsJSON.put("ret_url", retUrl); + paramsJSON.put("mer_inner_no", req.getMerInnerNo()); + paramsJSON.put("mer_cup_no", req.getMerCupNo()); + paramsJSON.put("contact_mobile", shopMchEntry.getLogin_mobile()); + paramsJSON.put("split_lowest_ratio", req.getSplitLowestRatio()); + paramsJSON.put("split_range", "MARK"); + paramsJSON.put("split_launch_mode", "MANUAL"); + paramsJSON.put("settle_type", "01"); + paramsJSON.put("split_rule_source", "TR"); + paramsJSON.put("ele_contract_no", ""); + paramsJSON.put("split_entrust_file_name", req.getSplitEntrustFileName()); + paramsJSON.put("split_entrust_file_path", splitEntrustFilePath); + + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { + return Pair.of(false, I18nUtil._("无返回值,申请开通分账失败!")); + } + + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + return Pair.of(false, lakalaRespJSON.getStr("retMsg")); + } + + paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); + paramsJSON.set("audit_status_text", paramsJSON.get("remark")); + paramsJSON.set("mch_id", shopMchEntry.getId()); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerMember lklLedgerMemberNew = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); + lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMemberNew); + + return Pair.of(true, I18nUtil._("提交成功,待审核中!")); + } catch (SDKException e) { + log.error("申请开通分账出错:", e); + return Pair.of(false, I18nUtil._("商家申请开通分账出错!")); +// throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); } } @@ -582,9 +696,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retMsg", "操作成功!"); log.info("商户分账申请业务回调:处理成功"); - // TODO 绑定接收方(平台方和代理商),绑定之前,判断是否已经绑定过了? - - + // 重要注:商户分账申请业务成功后,同时也会新增接收方,绑定接收方(平台方和代理商),绑定之前,判断是否已经绑定过了? + JSONObject bindParamsJSON = new JSONObject(); + bindParamsJSON.put("merInnerNo", paramsJSON.getStr("merInnerNo")); + bindParamsJSON.put("merCupNo", paramsJSON.getStr("merCupNo")); + Pair bindResult = innerApplyLedgerMerReceiverBind(bindParamsJSON); + if (bindResult.getFirst()) { + log.info("商户分账申请业务回调:", bindResult.getSecond()); + } else { + log.error("商户分账申请业务回调:", bindResult.getSecond()); + } } } @@ -700,7 +821,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } /** - * 分账关系绑定申请 + * 商家与平台、代理商分账关系绑定申请 * 参考:https://o.lakala.com/#/home/document/detail?id=386 * * @param paramsJSON @@ -790,6 +911,129 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } + /** + * 内部调用分账关系绑定申请 + * 参考:https://o.lakala.com/#/home/document/detail?id=386 + * + * @param paramsJSON + * @return + */ + public Pair innerApplyLedgerMerReceiverBind(JSONObject paramsJSON) { + // 检查分账方和接收方记录是否存在 + if (lklLedgerMemberService.getByMerCupNo(paramsJSON.getStr("merCupNo")) == null) { + return Pair.of(false, I18nUtil._("绑定方不存在!")); + } + + // 获取商家入驻记录 + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(paramsJSON.getStr("merCupNo")); + if (shopMchEntry == null) { + return Pair.of(false, I18nUtil._("商户入驻记录不存在!")); + } + + // 代理商Id,平台默认为0 + Long platformId = shopMchEntry.getDistributor_id(); + String entrustFileName = "小发同城合作协议书.pdf"; + String entrustFileUrl = shopMchEntry.getContract_download_url(); + + int successCnt = 0; + + // 获取平台接收方记录(可能多个记录,平台+代理商) + List lklLedgerReceiverList = lklLedgerReceiverService.getByCondition("", shopMchEntry.getLogin_mobile()); + if (CollectionUtils.isEmpty(lklLedgerReceiverList)) { + return Pair.of(false, I18nUtil._("分账接收方不存在!")); + } + + for (LklLedgerReceiver lklLedgerReceiver : lklLedgerReceiverList) { + LklLedgerMerReceiverBind lklLedgerMerReceiverBindOld = lklLedgerMerReceiverBindService.getByCondition(paramsJSON.getStr("merCupNo"), paramsJSON.getStr("receiverNo")); + if (lklLedgerMerReceiverBindOld != null) { + // return Pair.of(false, "分账绑定关系已存在!"); + continue; + } + + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyBindRequest req = new V2MmsOpenApiLedgerApplyBindRequest(); + + String orderNo = StringUtils.genLklOrderNo(8); // 8位随机数 + req.setOrderNo(orderNo); + req.setOrgCode(orgCode); + req.setVersion("2.0"); + + req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); + req.setMerCupNo(paramsJSON.getStr("merCupNo")); + req.setReceiverNo(lklLedgerReceiver.getReceiver_no()); + +// String fileName = paramsJSON.getStr("entrustFileName"); + String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(entrustFileUrl); // 这个是 url 地址,不是 base64 字节码 + req.setEntrustFileName(entrustFileName); + + String domain = projectDomain; + if (isProd()) { + domain += "/api"; + } + // 给拉卡拉通知的回调地址 + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify"; + req.setRetUrl(retUrl); + + // 文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(orderNo, + "SPLIT_COOPERATION_FILE", + StringUtils.getFileExt(entrustFileName), + splitEntrustFileBase64); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + // throw new ApiException(I18nUtil._("合作协议上传失败!")); + log.error(I18nUtil._("合作协议上传失败!")); + continue; + } + + String entrustFilePath = fileUploadResp.getStr("attFileId"); + req.setEntrustFilePath(entrustFilePath); + + paramsJSON.set("orderNo", orderNo); + paramsJSON.set("version", "2.0"); + paramsJSON.set("ret_url", retUrl); + paramsJSON.set("org_code", orgCode); + paramsJSON.set("entrust_file_name", entrustFileName); + paramsJSON.set("entrust_file_path", entrustFilePath); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { +// throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + log.error(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + continue; + } + + paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerMerReceiverBind lklLedgerMerReceiverBind = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMerReceiverBind.class); + if (lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(lklLedgerMerReceiverBind)) { + successCnt += 1; + } +// return Pair.of(true, "提交成功,待审核中!"); + } catch (SDKException e) { + log.error("分账绑定关系申请失败:", e); +// throw new ApiException(I18nUtil._("分账绑定关系申请失败!"), e); +// return Pair.of(false, "分账绑定关系申请失败!"); + } + } + + if (successCnt != lklLedgerReceiverList.size()) { + log.error("部分分账绑定关系提交成功"); + return Pair.of(true, "部分提交成功,待审核中!"); + } + + return Pair.of(true, "提交成功,待审核中!"); + } + /** * 分账关系绑定申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 @@ -832,7 +1076,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // TODO 新建一个正式的已审核通过的店铺, 新建之前判断是否已经新建过了? // 新建一个正式的已审核通过的店铺 ShopMchEntry shopEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); - if (shopEntry != null) { + if (shopEntry != null && !CommonConstant.Enable.equals(shopEntry.getStore_status())) { String mchMobile = shopEntry.getLogin_mobile(); Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(mchMobile); if (retPair.getFirst() > 0) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 1814594b..6cdae9eb 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -273,4 +273,24 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl getByCondition(String LicenseNo, String ContactMobile) { + + if (StrUtil.isBlank(LicenseNo) && StrUtil.isBlank(ContactMobile)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(LicenseNo)) { + queryWrapper.eq("license_no", LicenseNo); + } + if (StrUtil.isNotBlank(ContactMobile)) { + queryWrapper.eq("contact_mobile", ContactMobile); + } + + queryWrapper.eq("status", CommonConstant.Enable); + + return list(queryWrapper); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index a9abd30d..9a513550 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -140,7 +140,9 @@ public class LklTkServiceImpl { } protected boolean isProd() { - return "prod".equalsIgnoreCase(profile); + return false; + // 生产环境的时候启动该配置 + // return "prod".equalsIgnoreCase(profile); } /** @@ -156,17 +158,16 @@ public class LklTkServiceImpl { * @return */ public CommonResult uploadOcrImg(MultipartFile file, String imgType) { + UserDto currentUser = getCurrentUser(); + if (currentUser == null) { + currentUser = new UserDto(); + } if (file == null || StrUtil.isBlank(imgType)) { return CommonResult.failed("上传文件或图片类型不能为空"); } - UserDto user = getCurrentUser(); - if (user == null) { - return CommonResult.failed("请先登录"); - } - - CommonResult ossImgInfo = ossService.uploadFile(file, user); + CommonResult ossImgInfo = ossService.uploadFile(file, currentUser); if (ossImgInfo == null) { return CommonResult.failed("上传文件失败"); } @@ -511,8 +512,11 @@ public class LklTkServiceImpl { } // 公钥解密出来的数据 - String data = decryptNotifyData(notifyPubKeyPath, reqBodyJSON.getStr("data")); + String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath); + log.debug("解密公钥:{}", notifyPubKey); + String data = decryptNotifyData(notifyPubKey, reqBodyJSON.getStr("data")); log.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); + if (StrUtil.isBlank(data)) { return new JSONObject().set("code", "500").set("message", "参数解密出错"); } diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index e9dea6ae..087d50fe 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -191,7 +191,7 @@ lakala: #拉卡拉拓客进件配置 tk: #服务地址 - server_url: https://test.wsmsd.cn/sit/htkauth + server_url: https://test.wsmsd.cn client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt From 59473c5dc73fcc8233ea893916bcc5bad077f10c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 9 May 2025 12:05:37 +0800 Subject: [PATCH 16/39] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=EF=BC=8C=E5=92=8C=20bug=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/store/ShopMchEntry.java | 30 ++-- .../lakala/service/impl/LklTkServiceImpl.java | 163 ++++++++++-------- .../store/service/ShopMchEntryService.java | 5 +- .../service/impl/ShopMchEntryServiceImpl.java | 22 ++- .../src/main/resources/bootstrap-dev.yml | 1 + .../src/main/resources/bootstrap-local.yml | 1 + .../src/main/resources/bootstrap-prod.yml | 1 + .../src/main/resources/bootstrap-test.yml | 1 + .../src/main/resources/bootstrap-uat.yml | 1 + 9 files changed, 121 insertions(+), 104 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 3128033a..2338cdfa 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -117,14 +117,8 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "入驻商家营业执照的经营范围") private String biz_license_content; - @ApiModelProperty(value = "入驻商家的许可证类型:1-许可证;2-特许证件,3-其他证件") - private Integer license_type; - - @ApiModelProperty(value = "入驻商家的许可证编号") - private String license_number; - - @ApiModelProperty(value = "入驻商家许可证图片的存储路径") - private String license_image; + @ApiModelProperty(value = "营业执照以外的许可证信息列表JSON格式 [{'type':1,'number':'91450881MA5P8MWX69','img':'https://media-mall-prod-1259811287.cos.ap-guangzhou.myqcloud.com/1.png'}],type:1-许可证;2-特许证件,3-其他证件") + private String other_license_list; @ApiModelProperty(value = "商家营业执照有效开始时间") private String biz_license_period_begin; @@ -177,27 +171,27 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "个人身份证有效期结束时间") private String individual_id_period_end; - @ApiModelProperty(value = "入驻商家的开户⾏号") - private String bank_code; - - @ApiModelProperty(value = "入驻商家的开户银行") + @ApiModelProperty(value = "入驻商家的开户银行名称") private String bank_name; - @ApiModelProperty(value = "入驻商家开户银行的支行名称") - private String bank_branch_name; - - @ApiModelProperty(value = "结算账户清算⾏号") - private String clearing_bank_code; - @ApiModelProperty(value = "结算账户银行卡图片") private String bank_image; + @ApiModelProperty(value = "结算账号省市区code 省code/市code/区code,必填项") + private String bank_district; + @ApiModelProperty(value = "结算银行地区,格式: 省份/城市/乡县") private String bank_area; @ApiModelProperty(value = "结算账号类型:57-对公 58-对私") private String account_type; + @ApiModelProperty(value = "结算账户⾏号") + private String openning_bank_code; + + @ApiModelProperty(value = "结算账户清算⾏号") + private String clearing_bank_code; + @ApiModelProperty(value = "入驻商家的收款账户号码") private String account_number; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 9a513550..1493001a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -56,19 +56,20 @@ import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; @Service public class LklTkServiceImpl { - private static final Logger log = LoggerFactory.getLogger(LklTkServiceImpl.class); + private static final Logger logger = LoggerFactory.getLogger(LklTkServiceImpl.class); + @Value("${lakala.tk.server_url}") private String tkServerUrl; - @Value("${lakala.server_url}") - private String serverUrl; - @Value("${lakala.tk.client_id}") private String clientId; @Value("${lakala.tk.client_secret}") private String clientSecret; + @Value("${lakala.tk.user_no}") + private String userNo; + @Value("${lakala.org_code}") private String orgCode; @@ -78,6 +79,7 @@ public class LklTkServiceImpl { @Value("${spring.profiles.active}") private String profile; + @Lazy @Resource private ShopMchEntryService shopMchEntryService; @@ -123,11 +125,12 @@ public class LklTkServiceImpl { } return out.toString(); } catch (IllegalArgumentException e) { - System.err.println("Base64 解码时出现非法参数异常: " + e.getMessage()); + logger.error("Base64 解码时出现非法参数异常: ", e.getMessage()); } catch (Exception e) { // 捕获其他可能的异常,如 NoSuchAlgorithmException、NoSuchPaddingException、InvalidKeySpecException、InvalidKeyException、BadPaddingException 等 - System.err.println("解密过程中出现异常: " + e.getMessage()); + logger.error("解密过程中出现异常: ", e.getMessage()); } + return null; } @@ -135,10 +138,6 @@ public class LklTkServiceImpl { return tkServerUrl + urlPath; } - protected String buildLklServiceUrl(String urlPath) { - return serverUrl + urlPath; - } - protected boolean isProd() { return false; // 生产环境的时候启动该配置 @@ -214,40 +213,35 @@ public class LklTkServiceImpl { return CommonResult.failed("上传文件返回值有误"); } - - // 调用 OCR 识别接口 -// String ocrUrlPath = isProd() ? "/registration/ocr/result" : "/sit/htkregistration/ocr/result"; -// JSONObject ocrRequestBody = new JSONObject(); -// ocrRequestBody.put("batchNo", batchNo); -// ocrRequestBody.put("imgType", imgType); -// -// ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); -// if (ObjectUtil.isEmpty(ocrResponse) -// || ocrResponse.getStatusCode() != HttpStatus.OK -// || ObjectUtil.isEmpty(ocrResponse.getBody())) { -// return CommonResult.failed("OCR响应数据有误"); -// } -// -// -// JSONObject ocrObj = ocrResponse.getBody().get("result", JSONObject.class); -// if (ObjectUtil.isEmpty(ocrObj)) { -// return CommonResult.failed("OCR返回结果有误"); -// } -// -// ocrObj.put("lklUrl", updObj.getStr("url")); -// ocrObj.put("lklShowUrl", updObj.getStr("showUrl")); -// ocrObj.put("imgType", imgType); -// ocrObj.put("batchNo", batchNo); -// ocrObj.put("cosURL", imgURL); - - updObj.put("cosURL", imgURL); return CommonResult.success(updObj); } + /** + * 根据上传的图片的批次号,获取 OCR 识别结果 + * + * @param batchNo + * @param imgType * ID_CARD_FRONT 身份证正⾯ + * * ID_CARD_BEHIND 身份证反⾯ + * * BUSINESS_LICENCE 营业执照照⽚ + * * BANK_CARD 银行卡(企业对公不需要传) + * * AGREE_MENT 协议 + * * OPENING_PERMIT 开户许可证(企业对公需要传) + * * CHECKSTAND_IMG 收银台照片(必传) + * * SHOP_OUTSIDE_IMG 上传门头照片(必传) + * * SHOP_INSIDE_IMG 商铺内部照片(必传) + * * OTHERS 其他 无对应类型图片,请传其他类型 + * * SETTLE_ID_CARD_FRONT 结算人身份证人像面 + * * SETTLE_ID_CARD_BEHIND 结算人身份证国徽面 + * * LETTER_OF_AUTHORIZATION 法人授权涵 + * @return + */ public CommonResult imgOcrResult(String batchNo, String imgType) { + if (StrUtil.isBlank(batchNo) || StrUtil.isBlank(imgType)) { + return CommonResult.failed("批次号或图片类型不能为空"); + } // 调用 OCR 识别接口 String authorization = getLklTkAuthorization(); @@ -282,7 +276,7 @@ public class LklTkServiceImpl { } /** - * 请求获取token(商户进件) + * (商户进件前)请求获取token * * @return AuthorizationKey */ @@ -336,8 +330,7 @@ public class LklTkServiceImpl { } JSONObject formData = new JSONObject(); - formData.put("userNo", "29153396"); - + formData.put("userNo", userNo); formData.put("busiCode", "WECHAT_PAY");// WECHAT_PAY:专业化扫码;B2B_SYT:B2B收银台; formData.put("email", shopMchEntry.getEmail()); formData.put("merRegName", shopMchEntry.getStore_name()); @@ -346,8 +339,7 @@ public class LklTkServiceImpl { // 是企业类型商家 Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()); - String merType = isQy ? "TP_MERCHANT" : "TP_PERSONAL"; - formData.put("merType", merType); + formData.put("merType", isQy ? "TP_MERCHANT" : "TP_PERSONAL"); Map areaCode = getAreaCode(shopMchEntry.getStore_area(), false); if (ObjectUtil.isNotEmpty(areaCode)) { @@ -371,7 +363,7 @@ public class LklTkServiceImpl { formData.put("larName", larName); formData.put("larIdCard", larIdCard); formData.put("larIdCardStart", larIdCardStart); // 身份证有效期开始时间 - formData.put("larIdCardEnd", larIdCardEnd); // 身份证有效期结束时间 + formData.put("larIdCardEnd", larIdCardEnd); // 身份证有效期结束时间,长期:9999-12-31 // 营业执照上的经营内容 formData.put("businessContent", shopMchEntry.getSales_info()); @@ -381,13 +373,14 @@ public class LklTkServiceImpl { formData.put("licenseName", shopMchEntry.getBiz_license_company()); formData.put("licenseNo", shopMchEntry.getBiz_license_number()); formData.put("licenseDtStart", shopMchEntry.getBiz_license_period_begin()); - formData.put("licenseDtEnd", shopMchEntry.getBiz_license_period_end()); + formData.put("licenseDtEnd", shopMchEntry.getBiz_license_period_end()); // 长期:9999-12-31 } formData.put("contactMobile", mchMobile); formData.put("contactName", shopMchEntry.getContact_name()); - formData.put("openningBankCode", shopMchEntry.getBank_code());//结算账户开户⾏号 + // 银行账号关键字段 + formData.put("openningBankCode", shopMchEntry.getOpenning_bank_code());//结算账户开户⾏号 formData.put("openningBankName", shopMchEntry.getBank_name());//结算账户开户⾏名称 formData.put("clearingBankCode", shopMchEntry.getClearing_bank_code());//结算账户清算⾏号 @@ -411,7 +404,7 @@ public class LklTkServiceImpl { } } - // TODO 咨询清楚 + // TODO 咨询拉卡拉清楚 JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); bizContent.put("termNum", "1"); @@ -419,34 +412,34 @@ public class LklTkServiceImpl { bizContent.put("fees", new JSONArray() {{ put(new JSONObject() {{ put("feeCode", "WECHAT"); - put("feeValue", 0.20); + put("feeValue", 0.25); }}); }}); formData.put("bizContent", bizContent); // 附件文件相关开始 JSONArray attachments = new JSONArray(); - JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", true); + JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", false); if (ID_CARD_FRONT != null) { attachments.put(ID_CARD_FRONT); // 身份证正面 } - JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", true); + JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", false); if (ID_CARD_BEHIND != null) { attachments.put(ID_CARD_BEHIND); // 身份证国徽面 } - JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "SETTLE_ID_CARD_FRONT", true); + JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "SETTLE_ID_CARD_FRONT", false); if (SETTLE_ID_CARD_FRONT != null) { attachments.put(SETTLE_ID_CARD_FRONT); // 结算人身份证正面 } - JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "SETTLE_ID_CARD_BEHIND", true); + JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "SETTLE_ID_CARD_BEHIND", false); if (SETTLE_ID_CARD_BEHIND != null) { attachments.put(SETTLE_ID_CARD_BEHIND); // 结算人身份证国徽面 } - JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", true); + JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", false); if (BUSINESS_LICENCE != null) { attachments.put(BUSINESS_LICENCE); // 营业执照 } @@ -461,7 +454,7 @@ public class LklTkServiceImpl { attachments.put(SHOP_INSIDE_IMG); // 门店内部图片 } - JSONObject BANK_CARD = updatePhoto(shopMchEntry.getBank_image(), "BANK_CARD", true); + JSONObject BANK_CARD = updatePhoto(shopMchEntry.getBank_image(), "BANK_CARD", false); if (BANK_CARD != null) { attachments.put(BANK_CARD); // 银行卡图片 } @@ -469,10 +462,9 @@ public class LklTkServiceImpl { // 附件文件相关结束 String urlPath = isProd() ? "/registration/merchant" : "/sit/htkregistration/merchant"; - ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - String errMsg = "返回空或请求状态异常。"; + String errMsg = "进件返回空或请求状态异常"; if (ObjectUtil.isNotEmpty(response.getBody()) && ObjectUtil.isNotEmpty(response.getBody().getStr("message"))) { errMsg = response.getBody().getStr("message"); } @@ -480,8 +472,9 @@ public class LklTkServiceImpl { } // 更改入驻记录的拉卡拉内部商户号和进件请求参数 - String merchantNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 - Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, merchantNo, formData.toString()); + String lklMerCupNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 + // 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录 + Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerCupNo, lklMerCupNo, formData.toString()); if (!success) { return Pair.of(false, "提交进件成功,但更新商户号失败!"); } @@ -496,12 +489,12 @@ public class LklTkServiceImpl { * @return */ public JSONObject registrationMerchantNotify(HttpServletRequest request) { - log.debug("拉卡拉进件异步通知开始"); + logger.debug("拉卡拉进件异步通知开始"); JSONObject respData = new JSONObject(); // 解密请求参数 String requestBody = LakalaUtil.getBody(request); - log.debug("拉卡拉进件异步通知返回参数:{}", requestBody); + logger.debug("拉卡拉进件异步通知返回参数:{}", requestBody); if (StrUtil.isBlank(requestBody)) { return new JSONObject().set("code", "500").set("message", "返回参数为空"); } @@ -513,9 +506,9 @@ public class LklTkServiceImpl { // 公钥解密出来的数据 String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath); - log.debug("解密公钥:{}", notifyPubKey); + logger.debug("解密公钥:{}", notifyPubKey); String data = decryptNotifyData(notifyPubKey, reqBodyJSON.getStr("data")); - log.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); + logger.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); if (StrUtil.isBlank(data)) { return new JSONObject().set("code", "500").set("message", "参数解密出错"); @@ -527,18 +520,21 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "500").set("message", "参数解析出错"); } + // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 - Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merCupNo, dataJSON.getStr("customerNo"), CommonConstant.Enable, data); - if (!success) { - return new JSONObject().set("code", "500").set("message", "更新商户号失败"); - } + String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); if (ObjectUtil.isEmpty(shopMchEntry)) { return new JSONObject().set("code", "500").set("message", "商户入驻信息不存在"); } + Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, data); + if (!success) { + return new JSONObject().set("code", "500").set("message", "更新商户号失败"); + } + // 1、发起E签宝合同签署;签署完成之后,生成分账盖章协议书,下一步才能申请分账功能权限; esignContractService.innerSignFlowCreateByFile(shopMchEntry.getLogin_mobile()); @@ -579,7 +575,7 @@ public class LklTkServiceImpl { String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { - log.error("获取拉卡拉token失败"); + logger.error("获取拉卡拉token失败"); return retMap; } @@ -640,8 +636,28 @@ public class LklTkServiceImpl { return retMap; } + /** + * 上传进件相关图片和类型,返回图片ID和类型 + * + * @param fileUrl + * @param imgType ID_CARD_FRONT 身份证正⾯ + * ID_CARD_BEHIND 身份证反⾯ + * BUSINESS_LICENCE 营业执照照⽚ + * BANK_CARD 银行卡(企业对公不需要传) + * AGREE_MENT 协议 + * OPENING_PERMIT 开户许可证(企业对公需要传) + * CHECKSTAND_IMG 收银台照片(必传) + * SHOP_OUTSIDE_IMG 上传门头照片(必传) + * SHOP_INSIDE_IMG 商铺内部照片(必传) + * OTHERS 其他 无对应类型图片,请传其他类型 + * SETTLE_ID_CARD_FRONT 结算人身份证人像面 + * SETTLE_ID_CARD_BEHIND 结算人身份证国徽面 + * LETTER_OF_AUTHORIZATION 法人授权涵 + * @param isOcr + * @return + */ public JSONObject updatePhoto(String fileUrl, String imgType, Boolean isOcr) { - if (StrUtil.isBlank(fileUrl)) { + if (StrUtil.isBlank(fileUrl) || StrUtil.isBlank(imgType)) { return null; } @@ -655,23 +671,18 @@ public class LklTkServiceImpl { formData.put("sourcechnl", "0"); formData.put("isOcr", isOcr); - String urlPath = "/sit/htkregistration/file/upload"; - if (isProd()) { - urlPath = "/registration/file/upload"; - } + String urlPath = isProd() ? "/registration/file/upload" : "/sit/htkregistration/file/upload"; + ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { return null; } JSONObject result = response.getBody(); - if (result.isEmpty()) { + if (ObjectUtil.isEmpty(result)) { return null; } - JSONObject jsonObject = new JSONObject(); - jsonObject.put("id", result.get("url")); - jsonObject.put("type", imgType); - return jsonObject; + return new JSONObject().put("id", result.get("url")).put("type", imgType); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index fc38cc31..0e74dacd 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -141,11 +141,12 @@ public interface ShopMchEntryService { * * @param loginMobile * @param lklAuditStatus - * @param lklMerCupNo + * @param lklMerCupNo 拉卡拉银联商户号 + * @param lklMerInnerNo 拉卡拉内部商户号 * @param lklTkRegParams * @return */ - Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklTkRegParams); + Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklMerInnerNo, String lklTkRegParams); /** * 更新商家入驻申请的拉卡拉审核状态和响应数据 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index b62ca359..ea755a63 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -709,7 +709,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("lkl_mer_cup_no", lklMerCupNo); + updateWrapper.eq("lkl_mer_inner_no", lklInnerMerNo); if (ObjectUtil.isNotEmpty(lklAuditStatus)) { updateWrapper.set("lkl_audit_status", lklAuditStatus); } - if (StrUtil.isNotBlank(lklInnerMerNo)) { - updateWrapper.set("lkl_mer_inner_no", lklInnerMerNo); + + if (StrUtil.isNotBlank(lklMerCupNo)) { + updateWrapper.set("lkl_mer_cup_no", lklMerCupNo); } if (StrUtil.isNotBlank(lklTkRegResp)) { updateWrapper.set("lkl_tk_reg_resp", lklTkRegResp); diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index 5d1d3cb7..cb505b4e 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -167,6 +167,7 @@ lakala: server_url: https://test.wsmsd.cn/sit/htkauth client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 + user_no: 29153396 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index a809dd65..216eeb06 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -167,6 +167,7 @@ lakala: server_url: https://test.wsmsd.cn client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 + user_no: 29153396 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 087d50fe..a12f91c2 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -194,6 +194,7 @@ lakala: server_url: https://test.wsmsd.cn client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 + user_no: 29153396 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index f358d360..55d0859f 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -171,6 +171,7 @@ lakala: server_url: https://test.wsmsd.cn/sit/htkauth client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 + user_no: 29153396 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index f358d360..55d0859f 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -171,6 +171,7 @@ lakala: server_url: https://test.wsmsd.cn/sit/htkauth client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 + user_no: 29153396 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt From 1e5c8145c48f371b5e85268c7e646db7ec524f5d Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sat, 10 May 2025 14:47:42 +0800 Subject: [PATCH 17/39] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=E9=93=B6=E8=A1=8C=E6=8E=A5=E5=8F=A3=E8=BF=9B=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/modules/lakala/LklBanks.java | 58 ++++++ .../controller/mobile/LklTkController.java | 29 ++- .../shop/lakala/mapper/LklBanksMapper.java | 18 ++ .../shop/lakala/service/LklBanksService.java | 25 +++ .../service/impl/LklBanksServiceImpl.java | 58 ++++++ .../lakala/service/impl/LklTkServiceImpl.java | 192 +++++++++++------- .../mapper/lakala/LklBanksMapper.xml | 8 + .../mapper/lakala/LklLedgerMemberMapper.xml | 4 + .../lakala/LklLedgerMerReceiverBindMapper.xml | 4 + .../mapper/lakala/LklLedgerReceiverMapper.xml | 4 + 10 files changed, 320 insertions(+), 80 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklBanks.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklBanks.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklBanks.java new file mode 100644 index 00000000..d09e4bae --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklBanks.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.lakala; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("lkl_banks") +@ApiModel(value = "拉卡拉银行信息(包含账户行号、结清行号)", description = "拉卡拉银行信息(包含账户行号、结清行号)") +public class LklBanks implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "地区号") + private String area_code; + + @ApiModelProperty(value = "总行号") + private String bank_no; + + @ApiModelProperty(value = "银行名称") + private String branch_bank_name; + + @ApiModelProperty(value = "支行行号") + private String branch_bank_no; + + @ApiModelProperty(value = "结清行号") + private String clear_no; + + @ApiModelProperty(value = "记录状态:1-有效;2-无效;") + private Integer status; + + @ApiModelProperty(value = "记录创建时间") + private Date created_at; + + @ApiModelProperty(value = "记录更新时间") + private Date updated_at; +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index 39e8cb7c..2210a0fc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -9,17 +9,18 @@ package com.suisung.mall.shop.lakala.controller.mobile; import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.lakala.LklBanks; import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.lakala.service.LklBanksService; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; @@ -33,6 +34,26 @@ public class LklTkController extends BaseControllerImpl { @Resource private LklTkServiceImpl lklTkService; + @Resource + private LklBanksService lklBanksService; + + @ApiOperation(value = "搜索国内银行(支行)分页列表", notes = "搜索国内银行(支行)分页列表,数据包含有效的收款结清行号") + @RequestMapping(value = "/bank/search", method = RequestMethod.POST) + public CommonResult searchLklBanksPageList(@RequestBody JSONObject paramsJSON) { + Page list = lklBanksService.searchBranchBanksPageList(paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); + return CommonResult.success(list); + } + + @ApiOperation(value = "拉卡拉进件申请", notes = "拉卡拉进件申请") + @RequestMapping(value = "/registrationMerchant", method = {RequestMethod.POST, RequestMethod.GET}) + public CommonResult registrationMerchant(@RequestBody JSONObject paramsJSON) { + Pair resp = lklTkService.registrationMerchant(paramsJSON.getStr("mchMobile")); + if (resp.getFirst()) { + return CommonResult.success(null, resp.getSecond()); + } + + return CommonResult.failed(resp.getSecond()); + } // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify @ApiOperation(value = "拉卡拉进件申请异步回调通知", notes = "拉卡拉进件申请异步回调通知") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java new file mode 100644 index 00000000..fcf12d4e --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklBanks; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklBanksMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java new file mode 100644 index 00000000..347ac4cd --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.suisung.mall.common.modules.lakala.LklBanks; + +public interface LklBanksService { + + /** + * 根据关键字查询有效记录分页列表 + * + * @param keyword + * @param pageNum + * @param pageSize + * @return + */ + Page searchBranchBanksPageList(String keyword, Integer pageNum, Integer pageSize); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java new file mode 100644 index 00000000..6fe8fa91 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.suisung.mall.common.constant.CommonConstant; +import com.suisung.mall.common.modules.lakala.LklBanks; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.lakala.mapper.LklBanksMapper; +import com.suisung.mall.shop.lakala.service.LklBanksService; +import org.springframework.stereotype.Service; + +@Service +public class LklBanksServiceImpl extends BaseServiceImpl implements LklBanksService { + + + /** + * 根据关键字查询有效记录分页列表 + * + * @param keyword + * @param pageNum + * @param pageSize + * @return + */ + @Override + public Page searchBranchBanksPageList(String keyword, Integer pageNum, Integer pageSize) { + if (pageNum == null || pageNum < 1) { + pageNum = 1; + } + if (pageSize == null || pageSize < 1) { + pageSize = 10; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + + queryWrapper.eq("status", CommonConstant.Enable).orderByAsc("branch_bank_no"); + if (StrUtil.isNotBlank(keyword)) { + queryWrapper.and(wrapper -> wrapper + .like("branch_bank_name", keyword) + .or() + .like("branch_bank_no", keyword) + .or() + .like("clear_no", keyword) + .or() + .like("bank_no", keyword)); + } + + return lists(queryWrapper, pageNum, pageSize); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 1493001a..25ab2579 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -43,7 +43,6 @@ import javax.annotation.Resource; import javax.crypto.Cipher; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; -import java.io.File; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; @@ -199,24 +198,28 @@ public class LklTkServiceImpl { requestBody.put("sourcechnl", "0"); // 来源: 0:PC,1:安卓,2:IOS requestBody.put("isOcr", "true"); - ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); - if (ObjectUtil.isEmpty(updResponse) - || updResponse.getStatusCode() != HttpStatus.OK - || ObjectUtil.isEmpty(updResponse.getBody())) { - return CommonResult.failed("上传文件返回值有误"); + try { + ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); + if (ObjectUtil.isEmpty(updResponse) + || updResponse.getStatusCode() != HttpStatus.OK + || ObjectUtil.isEmpty(updResponse.getBody())) { + return CommonResult.failed("上传文件返回值有误"); + } + + // {batchNo,status,url,showUrl,result{} } + JSONObject updObj = updResponse.getBody(); + String batchNo = updObj.getStr("batchNo"); + if (StrUtil.isBlank(batchNo)) { + return CommonResult.failed("上传文件返回值有误"); + } + + updObj.put("cosURL", imgURL); + + return CommonResult.success(updObj); + } catch (Exception e) { + logger.error("上传文件失败: ", e.getMessage()); + return CommonResult.failed("上传文件失败:" + e.getMessage()); } - - // {batchNo,status,url,showUrl,result{} } - JSONObject updObj = updResponse.getBody(); - String batchNo = updObj.getStr("batchNo"); - if (StrUtil.isBlank(batchNo)) { - return CommonResult.failed("上传文件返回值有误"); - } - - updObj.put("cosURL", imgURL); - - return CommonResult.success(updObj); - } /** @@ -256,23 +259,26 @@ public class LklTkServiceImpl { JSONObject ocrRequestBody = new JSONObject(); ocrRequestBody.put("batchNo", batchNo); ocrRequestBody.put("imgType", imgType); + logger.info("ocr请求参数:{}", ocrRequestBody); + try { + ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); + if (ObjectUtil.isEmpty(ocrResponse) + || ocrResponse.getStatusCode() != HttpStatus.OK + || ObjectUtil.isEmpty(ocrResponse.getBody())) { + return CommonResult.failed("OCR响应数据有误"); + } - ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); - if (ObjectUtil.isEmpty(ocrResponse) - || ocrResponse.getStatusCode() != HttpStatus.OK - || ObjectUtil.isEmpty(ocrResponse.getBody())) { - return CommonResult.failed("OCR响应数据有误"); + JSONObject ocrObj = ocrResponse.getBody().get("result", JSONObject.class); + logger.info("ocr返回结果:{}", ocrResponse); + if (ObjectUtil.isEmpty(ocrObj)) { + return CommonResult.failed("OCR返回结果有误"); + } + + return CommonResult.success(ocrObj); + } catch (Exception e) { + logger.error("OCR识别失败: ", e.getMessage()); + return CommonResult.failed("OCR识别失败:" + e.getMessage()); } - - - JSONObject ocrObj = ocrResponse.getBody().get("result", JSONObject.class); - if (ObjectUtil.isEmpty(ocrObj)) { - return CommonResult.failed("OCR返回结果有误"); - } - - - return CommonResult.success(ocrObj); - } /** @@ -310,6 +316,8 @@ public class LklTkServiceImpl { /** * (重要) 请求拉卡拉进件 + *

+ * 参考拉卡拉给的独立文档:2、拓客SAAS商户管理接口(新).docx * * @param mchMobile 商家手机号 * @return @@ -341,12 +349,6 @@ public class LklTkServiceImpl { Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()); formData.put("merType", isQy ? "TP_MERCHANT" : "TP_PERSONAL"); - Map areaCode = getAreaCode(shopMchEntry.getStore_area(), false); - if (ObjectUtil.isNotEmpty(areaCode)) { - formData.put("provinceCode", areaCode.get("provinceCode")); - formData.put("cityCode", areaCode.get("cityCode")); - formData.put("countyCode", areaCode.get("countyCode")); - } formData.put("longtude", shopMchEntry.getStore_longitude()); //longitude 经度 formData.put("latitude", shopMchEntry.getStore_latitude()); @@ -390,9 +392,18 @@ public class LklTkServiceImpl { formData.put("accountIdCard", shopMchEntry.getLegal_person_id_number());//结算⼈证件号码(身份证) formData.put("settleType", "D1"); //结算类型,D0秒到,D1次日结算 - formData.put("settlementType", "AUTOMATIC"); // 结算方式:MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持) + // formData.put("settlementType", "AUTOMATIC"); // 结算方式:MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持) - //结算信息省份代码 + + // 店铺省市区信息 + Map areaCode = getAreaCode(shopMchEntry.getStore_area(), false); + if (ObjectUtil.isNotEmpty(areaCode)) { + formData.put("provinceCode", areaCode.get("provinceCode")); + formData.put("cityCode", areaCode.get("cityCode")); + formData.put("countyCode", areaCode.get("countyCode")); + } + + //结算信息省市信息 Map bankAreaCode = getAreaCode(shopMchEntry.getBank_area(), true); if (ObjectUtil.isNotEmpty(bankAreaCode)) { formData.put("settleProvinceCode", bankAreaCode.get("provinceCode")); @@ -404,6 +415,7 @@ public class LklTkServiceImpl { } } + // TODO 咨询拉卡拉清楚 JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); @@ -412,7 +424,7 @@ public class LklTkServiceImpl { bizContent.put("fees", new JSONArray() {{ put(new JSONObject() {{ put("feeCode", "WECHAT"); - put("feeValue", 0.25); + put("feeValue", 0.38); }}); }}); formData.put("bizContent", bizContent); @@ -429,14 +441,14 @@ public class LklTkServiceImpl { attachments.put(ID_CARD_BEHIND); // 身份证国徽面 } - JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "SETTLE_ID_CARD_FRONT", false); + JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "FR_ID_CARD_FRONT", false); if (SETTLE_ID_CARD_FRONT != null) { - attachments.put(SETTLE_ID_CARD_FRONT); // 结算人身份证正面 + attachments.put(SETTLE_ID_CARD_FRONT); // 法人身份证正面 } - JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "SETTLE_ID_CARD_BEHIND", false); + JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "FR_ID_CARD_BEHIND", false); if (SETTLE_ID_CARD_BEHIND != null) { - attachments.put(SETTLE_ID_CARD_BEHIND); // 结算人身份证国徽面 + attachments.put(SETTLE_ID_CARD_BEHIND); // 法人身份证国徽面 } JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", false); @@ -462,21 +474,28 @@ public class LklTkServiceImpl { // 附件文件相关结束 String urlPath = isProd() ? "/registration/merchant" : "/sit/htkregistration/merchant"; - ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); - if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - String errMsg = "进件返回空或请求状态异常"; - if (ObjectUtil.isNotEmpty(response.getBody()) && ObjectUtil.isNotEmpty(response.getBody().getStr("message"))) { - errMsg = response.getBody().getStr("message"); - } - return Pair.of(false, "进件失败:" + errMsg); - } + try { + logger.info("进件请求参数:{}", JSONUtil.toJsonStr(formData)); - // 更改入驻记录的拉卡拉内部商户号和进件请求参数 - String lklMerCupNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 - // 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录 - Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerCupNo, lklMerCupNo, formData.toString()); - if (!success) { - return Pair.of(false, "提交进件成功,但更新商户号失败!"); + ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); + if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { + String errMsg = "进件返回空或请求状态异常"; + if (ObjectUtil.isNotEmpty(response.getBody()) && ObjectUtil.isNotEmpty(response.getBody().getStr("message"))) { + errMsg = response.getBody().getStr("message"); + } + return Pair.of(false, "进件失败:" + errMsg); + } + + // 更改入驻记录的拉卡拉内部商户号和进件请求参数 + String lklMerCupNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 + // 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录 + Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerCupNo, lklMerCupNo, formData.toString()); + if (!success) { + return Pair.of(false, "提交进件成功,但更新商户号失败!"); + } + } catch (Exception e) { + logger.error("拉卡拉进件异常:{}", e.getMessage()); + return Pair.of(false, "进件失败:" + e.getMessage()); } return Pair.of(true, "提交进件成功,请等待审核!"); @@ -520,7 +539,6 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "500").set("message", "参数解析出错"); } - // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 @@ -564,6 +582,10 @@ public class LklTkServiceImpl { } String provinceName = areaNames[0]; + // 因为5个自治区需要简称,所以去掉 壮族,回族,维吾尔族 + provinceName = StrUtil.replace(provinceName, "壮族", "") + .replace("回族", "") + .replace("维吾尔族", "").replace("自治区", ""); String cityName = areaNames[1]; String countryName = ""; if (areaNames.length >= 3) { @@ -592,6 +614,7 @@ public class LklTkServiceImpl { JSONArray jsonArray = response.getBody(); if (CollUtil.isNotEmpty(jsonArray)) { +// logger.info("省份列表:{}", jsonArray.toString()); // 省份列表 for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), provinceName)) { @@ -606,6 +629,7 @@ public class LklTkServiceImpl { response = RestTemplateHttpUtil.sendGetWithHeader(buildLklTkUrl(urlPath + "/" + provinceCode), header, JSONArray.class); jsonArray = response.getBody(); if (CollUtil.isNotEmpty(jsonArray)) { +// logger.info("城市列表:{}", jsonArray.toString()); for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), cityName)) { cityCode = jsonObject.getStr("code"); @@ -621,6 +645,7 @@ public class LklTkServiceImpl { response = RestTemplateHttpUtil.sendGetWithHeader(buildLklTkUrl(urlPath + "/" + cityCode), header, JSONArray.class); jsonArray = response.getBody(); if (CollUtil.isNotEmpty(jsonArray)) { +// logger.info("区列表:{}", jsonArray.toString()); for (JSONObject jsonObject : jsonArray.jsonIter()) { if (StrUtil.contains(jsonObject.getStr("name"), countryName)) { countyCode = jsonObject.getStr("code"); @@ -642,6 +667,8 @@ public class LklTkServiceImpl { * @param fileUrl * @param imgType ID_CARD_FRONT 身份证正⾯ * ID_CARD_BEHIND 身份证反⾯ + * FR_ID_CARD_FRONT 身份证正⾯ + * FR_ID_CARD_BEHIND 身份证反⾯ * BUSINESS_LICENCE 营业执照照⽚ * BANK_CARD 银行卡(企业对公不需要传) * AGREE_MENT 协议 @@ -664,25 +691,38 @@ public class LklTkServiceImpl { JSONObject header = new JSONObject(); header.put("Authorization", getLklTkAuthorization()); - JSONObject formData = new JSONObject(); - File file = UploadUtil.downloadImageFromUrl(fileUrl); - formData.put("file", file); - formData.put("imgType", imgType); - formData.put("sourcechnl", "0"); - formData.put("isOcr", isOcr); - - String urlPath = isProd() ? "/registration/file/upload" : "/sit/htkregistration/file/upload"; - - ResponseEntity response = RestTemplateHttpUtil.sendPostFormDataBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); - if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { + String updUrlPath = isProd() ? "/registration/file/base/upload" : "/sit/htkregistration/file/base/upload"; + String fileBase64 = UploadUtil.fileUrlToBase64(fileUrl); + if (StrUtil.isBlank(fileBase64)) { + logger.error("文件转换失败"); return null; } - JSONObject result = response.getBody(); - if (ObjectUtil.isEmpty(result)) { + // Base64Utils.encodeToString(file.getBytes()); + + JSONObject requestBody = new JSONObject(); + requestBody.put("fileBase64", fileBase64); + requestBody.put("imgType", imgType); + requestBody.put("sourcechnl", "0"); // 来源: 0:PC,1:安卓,2:IOS + requestBody.put("isOcr", "true"); + + try { + ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); + if (ObjectUtil.isEmpty(updResponse) + || updResponse.getStatusCode() != HttpStatus.OK) { + logger.error("上传文件返回值有误"); + return null; + } + + JSONObject result = updResponse.getBody(); + if (ObjectUtil.isEmpty(result)) { + return null; + } + + return new JSONObject().put("id", result.get("url")).put("type", imgType); + } catch (Exception e) { + logger.error("上传文件异常:{}", e.getMessage()); return null; } - - return new JSONObject().put("id", result.get("url")).put("type", imgType); } diff --git a/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml new file mode 100644 index 00000000..8e026578 --- /dev/null +++ b/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml @@ -0,0 +1,8 @@ + + + + + + * + + diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerMemberMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMemberMapper.xml index 4ab65aa7..71d4113d 100644 --- a/mall-shop/src/main/resources/mapper/lakala/LklLedgerMemberMapper.xml +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMemberMapper.xml @@ -1,4 +1,8 @@ + + + * + diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml index 3e060b7a..779aa2a5 100644 --- a/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerMerReceiverBindMapper.xml @@ -1,4 +1,8 @@ + + + * + diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml index 2b03205c..2d80129e 100644 --- a/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerReceiverMapper.xml @@ -1,4 +1,8 @@ + + + * + From 764ebfbc48148f3d653aaab0a2b1aee620b6a05c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sat, 10 May 2025 16:12:16 +0800 Subject: [PATCH 18/39] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=95=86=E5=AE=B6?= =?UTF-8?q?=E5=88=86=E8=B4=A6=E7=9A=84=E5=9B=9B=E4=B8=AA=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/EsignContractServiceImpl.java | 24 +++---- .../service/LklLedgerMemberService.java | 3 +- .../service/impl/LakalaApiServiceImpl.java | 22 +++++-- .../impl/LklLedgerMemberServiceImpl.java | 62 +++++++++++-------- .../lakala/service/impl/LklTkServiceImpl.java | 2 +- .../service/impl/ShopMchEntryServiceImpl.java | 5 ++ 6 files changed, 70 insertions(+), 48 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index 9cf8d63b..de4743dd 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -33,6 +33,7 @@ import com.suisung.mall.shop.esign.utils.comm.EsignHttpResponse; import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; import com.suisung.mall.shop.lakala.service.LakalaApiService; +import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; import com.suisung.mall.shop.page.service.OssService; import com.suisung.mall.shop.store.service.ShopMchEntryService; import com.suisung.mall.shop.store.service.ShopStoreBaseService; @@ -97,6 +98,11 @@ public class EsignContractServiceImpl extends BaseServiceImpl { - // 1、(电子合同)给商家申请分账功能使用; - - // 新建一个正式的已审核通过的店铺 -// Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(esignContract.getMch_mobile()); -// if (retPair.getFirst() > 0) { -// // 更改合同记录表的店铺id -// updateContractStoreId(esignContract.getMch_mobile(), retPair.getFirst()); -// // 填充合同模版表的店铺Id -// esignContractFillingFileService.updateContractFillingStoreId(esignContract.getMch_mobile(), retPair.getFirst()); -// // 店铺创建状态已完成 -// shopMchEntryService.updateMerchEntryStoreStatus(esignContract.getMch_mobile(), CommonConstant.Enable); -// } - - // }); + // 更新商家的hasEsigned状态=1 + lklLedgerMemberService.updateMulStatus("", esignContract.getMch_mobile(), 1, 0, 0, 0); return new ResponseEntity<>(new JSONObject().put("code", 200).put("msg", "success").toString(), HttpStatus.OK); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index 566090cf..40a2e042 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -58,11 +58,12 @@ public interface LklLedgerMemberService extends IBaseService { * 更新分账多个状态 * * @param merCupNo + * @param mchMobile * @param hasEsigned * @param hasApplySplit * @param hasReceiver * @param hasBindReceiver * @return */ - Boolean updateMulStatus(String merCupNo, Integer hasEsigned, Integer hasApplySplit, Integer hasReceiver, Integer hasBindReceiver); + Boolean updateMulStatus(String merCupNo, String mchMobile, Integer hasEsigned, Integer hasApplySplit, Integer hasReceiver, Integer hasBindReceiver); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index a7199955..cd8b6b78 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -61,7 +61,7 @@ import java.util.List; public class LakalaApiServiceImpl implements LakalaApiService { private static final boolean init = false; private static final String lklSuccessCode = "000000"; - //### 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 + // 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 @Value("${lakala.merchant_no}") public String merchantNo; // 拉卡拉分配的商户号 @Value("${lakala.term_no}") @@ -553,7 +553,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(true, I18nUtil._("商家已经申请过了!")); } - // 1. 配置初始化 initLKLSDK(); @@ -681,6 +680,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } // 更改本地分账记录状态数据 + String merCupNo = paramsJSON.getStr("merCupNo"); Boolean success = lklLedgerMemberService.updateAuditResult(applyId, paramsJSON.getStr("merInnerNo"), paramsJSON.getStr("merCupNo"), @@ -696,16 +696,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retMsg", "操作成功!"); log.info("商户分账申请业务回调:处理成功"); - // 重要注:商户分账申请业务成功后,同时也会新增接收方,绑定接收方(平台方和代理商),绑定之前,判断是否已经绑定过了? + // 重要注:商户分账申请业务成功后,同时也会新增接收方,这时系统绑定接收方(平台方和代理商),绑定之前,要判断是否已经绑定过了? JSONObject bindParamsJSON = new JSONObject(); bindParamsJSON.put("merInnerNo", paramsJSON.getStr("merInnerNo")); - bindParamsJSON.put("merCupNo", paramsJSON.getStr("merCupNo")); + bindParamsJSON.put("merCupNo", merCupNo); Pair bindResult = innerApplyLedgerMerReceiverBind(bindParamsJSON); if (bindResult.getFirst()) { log.info("商户分账申请业务回调:", bindResult.getSecond()); } else { log.error("商户分账申请业务回调:", bindResult.getSecond()); } + + // 更新商家的hasApplySplit状态=1 + lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 1, 0, 0); + } } @@ -738,8 +742,10 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setOrgCode(orgCode); req.setVersion("2.0"); + String mchMobile = paramsJSON.getStr("contactMobile"); + req.setReceiverName(paramsJSON.getStr("receiverName")); - req.setContactMobile(paramsJSON.getStr("contactMobile")); + req.setContactMobile(mchMobile); req.setLicenseNo(paramsJSON.getStr("licenseNo")); req.setLicenseName(paramsJSON.getStr("licenseName")); @@ -812,6 +818,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.error("接收方创建成功,但更新本地数据 lklLedgerReceiverService.saveOrUpdateByReceiverNo 失败!"); } + // 更新商家的has_receiver状态=1 + lklLedgerMemberService.updateMulStatus("", mchMobile, 0, 0, 1, 0); + return CommonResult.success(lklLedgerReceiver, "创建接收方成功!"); } catch (SDKException e) { @@ -1073,6 +1082,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (success) { respData.put("retCode", lklSuccessCode); + // 更改商家的状态 has_bind_receiver 状态=1 + lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 0, 0, 1); + // TODO 新建一个正式的已审核通过的店铺, 新建之前判断是否已经新建过了? // 新建一个正式的已审核通过的店铺 ShopMchEntry shopEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java index c1b61a65..b944cf6b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -128,6 +128,7 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("mer_cup_no", merCupNo); - if (hasEsigned != null && hasEsigned > 0) { - i++; - updateWrapper.set("has_esigned", hasEsigned); - } - if (hasApplySplit != null && hasApplySplit > 0) { - i++; - updateWrapper.set("has_apply_split", hasApplySplit); - } - if (hasReceiver != null && hasReceiver > 0) { - i++; - updateWrapper.set("has_receiver", hasReceiver); - } - if (hasBindReceiver != null && hasBindReceiver > 0) { - i++; - updateWrapper.set("has_bind_receiver", hasBindReceiver); - } + try { + int i = 0; + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + if (StrUtil.isNotBlank(mchMobile)) { + updateWrapper.eq("mch_mobile", mchMobile); + } + if (StrUtil.isNotBlank(merCupNo)) { + updateWrapper.eq("mer_cup_no", merCupNo); + } - if (i == 0) { + if (hasEsigned != null && hasEsigned > 0) { + i++; + updateWrapper.set("has_esigned", hasEsigned); + } + if (hasApplySplit != null && hasApplySplit > 0) { + i++; + updateWrapper.set("has_apply_split", hasApplySplit); + } + if (hasReceiver != null && hasReceiver > 0) { + i++; + updateWrapper.set("has_receiver", hasReceiver); + } + if (hasBindReceiver != null && hasBindReceiver > 0) { + i++; + updateWrapper.set("has_bind_receiver", hasBindReceiver); + } + + if (i == 0) { + return false; + } + + return update(updateWrapper); + } catch (Exception e) { + log.error("更新分账商家多个状态失败", e); return false; } - - return update(updateWrapper); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 25ab2579..5fa8957f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -368,7 +368,7 @@ public class LklTkServiceImpl { formData.put("larIdCardEnd", larIdCardEnd); // 身份证有效期结束时间,长期:9999-12-31 // 营业执照上的经营内容 - formData.put("businessContent", shopMchEntry.getSales_info()); + formData.put("businessContent", shopMchEntry.getBiz_license_content()); // 营业执照信息 if (isQy) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index ea755a63..eaa11796 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -205,6 +205,11 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl Date: Sun, 11 May 2025 22:37:35 +0800 Subject: [PATCH 19/39] =?UTF-8?q?=E5=85=A5=E9=A9=BB=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E8=B0=83=E6=95=B4=EF=BC=8Cbug=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/constant/CommonConstant.java | 3 +- .../common/modules/store/ShopMchEntry.java | 15 ++-- .../controller/mobile/LklTkController.java | 2 +- .../impl/LklLedgerReceiverServiceImpl.java | 2 +- .../lakala/service/impl/LklTkServiceImpl.java | 29 ++++++-- .../service/impl/ShopMchEntryServiceImpl.java | 70 +++++++++++++------ .../impl/ShopStoreBaseServiceImpl.java | 21 ++++-- 7 files changed, 96 insertions(+), 46 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java index fec451e9..4d84e506 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java +++ b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java @@ -45,11 +45,12 @@ public class CommonConstant { public static final Integer PRODUCT_DATA_SOURCE_USER = 1; public static final Integer PRODUCT_DATA_SOURCE_SX = 2; - // 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请; + // 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核; public static final Integer MCH_APPR_STA_PASS = 1; public static final Integer MCH_APPR_STA_NOPASS = 2; public static final Integer MCH_APPR_STA_PADDING = 3; public static final Integer MCH_APPR_STA_NONE = 4; + public static final Integer MCH_APPR_STA_LKL_PADDING = 5; // 入驻商家主体类型,企业或个人:1-企业;2-个人; public static final Integer MCH_ENTITY_TYPE_QY = 1; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 2338cdfa..44600acc 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -81,16 +81,11 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "邮箱") private String email; - @ApiModelProperty(value = "入驻商家店铺所在的省") - private String province_id; - @ApiModelProperty(value = "入驻商家店铺所在的市") - private String city_id; + @ApiModelProperty(value = "店铺地区编号,省份code/城市code/区code") + private String store_district; - @ApiModelProperty(value = "入驻商家店铺所在的县区") - private String county_id; - - @ApiModelProperty(value = "店铺地区 省份/城市/乡县") + @ApiModelProperty(value = "店铺地区名称,省份/城市/区") private String store_area; @ApiModelProperty(value = "入驻商家店铺的详细地址") @@ -177,10 +172,10 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "结算账户银行卡图片") private String bank_image; - @ApiModelProperty(value = "结算账号省市区code 省code/市code/区code,必填项") + @ApiModelProperty(value = "结算账号省市区编号 省code/市code/区code,必填项") private String bank_district; - @ApiModelProperty(value = "结算银行地区,格式: 省份/城市/乡县") + @ApiModelProperty(value = "结算银行地区名称,格式: 省份/城市/区") private String bank_area; @ApiModelProperty(value = "结算账号类型:57-对公 58-对私") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index 2210a0fc..e5a31ae2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -47,7 +47,7 @@ public class LklTkController extends BaseControllerImpl { @ApiOperation(value = "拉卡拉进件申请", notes = "拉卡拉进件申请") @RequestMapping(value = "/registrationMerchant", method = {RequestMethod.POST, RequestMethod.GET}) public CommonResult registrationMerchant(@RequestBody JSONObject paramsJSON) { - Pair resp = lklTkService.registrationMerchant(paramsJSON.getStr("mchMobile")); + Pair resp = lklTkService.registrationMerchant(paramsJSON.getStr("mchMobile"), paramsJSON.getStr("bizLicenseNumber")); if (resp.getFirst()) { return CommonResult.success(null, resp.getSecond()); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 6cdae9eb..06672786 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -218,7 +218,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl registrationMerchant(String mchMobile) { + public Pair registrationMerchant(String mchMobile, String bizLicenseNumber) { String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { return Pair.of(false, "获取拉卡拉token失败"); @@ -332,7 +337,7 @@ public class LklTkServiceImpl { header.put("Authorization", getLklTkAuthorization()); // 获取商家入驻信息,组成请求参数 - ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, null, CommonConstant.MCH_APPR_STA_PASS); + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, bizLicenseNumber, CommonConstant.MCH_APPR_STA_LKL_PADDING); if (ObjectUtil.isEmpty(shopMchEntry)) { return Pair.of(false, "商家入驻信息不存在"); } @@ -420,7 +425,7 @@ public class LklTkServiceImpl { JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); bizContent.put("termNum", "1"); - bizContent.put("mcc", "12015"); // 超市的 code + bizContent.put("mcc", "5311"); // 超市的 code bizContent.put("fees", new JSONArray() {{ put(new JSONObject() {{ put("feeCode", "WECHAT"); @@ -493,6 +498,7 @@ public class LklTkServiceImpl { if (!success) { return Pair.of(false, "提交进件成功,但更新商户号失败!"); } + } catch (Exception e) { logger.error("拉卡拉进件异常:{}", e.getMessage()); return Pair.of(false, "进件失败:" + e.getMessage()); @@ -553,11 +559,24 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "500").set("message", "更新商户号失败"); } + logger.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###"); + // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 + Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(shopMchEntry.getLogin_mobile(), ""); + if (!genSuccess) { + logger.error("###商家入驻电子合同生成失败###"); + } + // 1、发起E签宝合同签署;签署完成之后,生成分账盖章协议书,下一步才能申请分账功能权限; - esignContractService.innerSignFlowCreateByFile(shopMchEntry.getLogin_mobile()); + Pair resPair = esignContractService.innerSignFlowCreateByFile(shopMchEntry.getLogin_mobile()); + if (!resPair.getFirst()) { + logger.error("###商家发起电子签名失败:{}###", resPair.getSecond()); + } // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 - lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); + genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); + if (!genSuccess) { + logger.error("###申请分账接收方失败###"); + } return new JSONObject().set("code", "200").set("message", "成功"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index eaa11796..ca14330d 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -30,6 +30,7 @@ import com.suisung.mall.shop.components.TaskService; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; +import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import com.suisung.mall.shop.message.service.ShopMessageTemplateService; import com.suisung.mall.shop.store.mapper.ShopMchEntryMapper; import com.suisung.mall.shop.store.service.ShopMchEntryService; @@ -76,6 +77,10 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); - if (approvalStatus.equals(CommonConstant.Enable) && StrUtil.isBlank(approvalRemark)) { + if (approvalStatus.equals(CommonConstant.MCH_APPR_STA_LKL_PADDING) && StrUtil.isBlank(approvalRemark)) { // 审核通过 - approvalRemark = "审核通过,后续将向您发起签署电子合同流程。"; + approvalRemark = "初步审核通过,等待进一步审核。";//"审核通过,后续将向您发起签署电子合同流程。"; updateWrapper.set("signed_status", CommonConstant.CONTRACT_SIGN_STA_ING); - } else if (approvalStatus.equals(CommonConstant.Disable2) && StrUtil.isBlank(approvalRemark)) { + updateWrapper.set("approval_status", CommonConstant.MCH_APPR_STA_LKL_PADDING); // 进入拉卡拉审核中 + + log.info("准备提交给拉卡拉进件审核。"); + } else if (approvalStatus.equals(CommonConstant.MCH_APPR_STA_NOPASS) && StrUtil.isBlank(approvalRemark)) { approvalRemark = "审核未通过,请继续完善入驻资料信息。"; } - // 自动计算商家分成比例 + // 重要备注:自动计算商家分成比例 record.setSplit_ratio(shopBaseStoreCategoryService.getStoreCategoryRatio(record.getBiz_category())); updateWrapper.eq("id", id) @@ -496,21 +513,26 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl { - log.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###"); - // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 - Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getLogin_mobile(), ""); - if (!genSuccess) { - log.error("###商家入驻电子合同生成失败###"); - } - - // 发短信通知商家,入驻申请已通过审核 - }); + // TODO 审核通过后,触发去拉卡拉进件,系统审核 + Pair resultPair = lklTkService.registrationMerchant(record.getLogin_mobile(), record.getBiz_license_number()); + if (!resultPair.getFirst()) { + return CommonResult.failed(resultPair.getSecond()); } +// if (approvalStatus.equals(CommonConstant.Enable)) { +// // 多线程执行电子合同生成和填充 +// taskService.executeTask(() -> { +// log.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###"); +// // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 +// Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getLogin_mobile(), ""); +// if (!genSuccess) { +// log.error("###商家入驻电子合同生成失败###"); +// } +// +// // 发短信通知商家,入驻申请已通过审核 +// }); +// } + return CommonResult.success(); } @@ -631,7 +653,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl districtList = shopBaseDistrictService.getFullDistrictByDistrictCode(shopMchEntry.getCounty_id()); - shopStoreBase.setStore_district_id(shopBaseDistrictService.joinDistrict(districtList, 1, true, "/")); - shopStoreBase.setStore_area(shopBaseDistrictService.joinDistrict(districtList, 2, true, "/")); + // List districtList = shopBaseDistrictService.getFullDistrictByDistrictCode(shopMchEntry.getCounty_id()); + //shopStoreBase.setStore_district_id(shopBaseDistrictService.joinDistrict(districtList, 1, true, "/")); + // shopStoreBase.setStore_area(shopBaseDistrictService.joinDistrict(districtList, 2, true, "/")); + + shopStoreBase.setStore_district_id(shopMchEntry.getStore_district()); + shopStoreBase.setStore_area(shopMchEntry.getStore_area()); shopStoreBase.setStore_address(shopMchEntry.getStore_address()); shopStoreBase.setStore_longitude(shopMchEntry.getStore_longitude()); shopStoreBase.setStore_latitude(shopMchEntry.getStore_latitude()); From fe3a25b35261a3b89235274782429615c911f21c Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Mon, 12 May 2025 23:29:16 +0800 Subject: [PATCH 20/39] =?UTF-8?q?=E9=93=B6=E8=A1=8C=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=88=86=E8=AF=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mall-common/pom.xml | 29 ++++++----- .../suisung/mall/common/utils/JiebaUtils.java | 48 +++++++++++++++++++ .../suisung/mall/shop/components/IpUtil.java | 9 +++- .../service/impl/LklBanksServiceImpl.java | 34 +++++++++---- .../lakala/service/impl/LklTkServiceImpl.java | 32 ++++++++----- .../store/service/ShopMchEntryService.java | 4 +- .../service/impl/ShopMchEntryServiceImpl.java | 20 ++++---- 7 files changed, 127 insertions(+), 49 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java diff --git a/mall-common/pom.xml b/mall-common/pom.xml index e679edd6..3af6b2f1 100644 --- a/mall-common/pom.xml +++ b/mall-common/pom.xml @@ -102,19 +102,19 @@ - - - - - - + + + + + + - - - - - - + + + + + + @@ -274,6 +274,11 @@ spring-boot-starter-freemarker + + com.huaban + jieba-analysis + 1.0.2 + diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java new file mode 100644 index 00000000..ba6c7760 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.utils; + +import com.huaban.analysis.jieba.JiebaSegmenter; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class JiebaUtils { + + private final JiebaSegmenter segmenter = new JiebaSegmenter(); + + public static void main(String[] args) { + JiebaUtils jiebaUtils = new JiebaUtils(); + String text = "中国工商银行桂平市光明支行"; + List words = jiebaUtils.segmentForSearch(text); + System.out.println(words); + } + + /** + * 精确模式分词 + */ + public List segment(String text) { + return segmenter.process(text, JiebaSegmenter.SegMode.INDEX) + .stream() + .map(token -> token.word) + .collect(Collectors.toList()); + } + + /** + * 搜索模式分词(更细粒度) + */ + public List segmentForSearch(String text) { + return segmenter.process(text, JiebaSegmenter.SegMode.SEARCH) + .stream() + .map(token -> token.word) + .collect(Collectors.toList()); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java b/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java index 6c4ef10b..21c13e73 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/components/IpUtil.java @@ -29,11 +29,16 @@ public class IpUtil implements ApplicationRunner { log.error("IP2RegionUtils 没有成功加载数据文件"); return null; } + + if (CheckUtil.isEmpty(ip)) { + return null; + } + try { return searcher.search(ip); } catch (Exception e) { - log.error("IP:{} 格式错误:{}", ip, e); - return null; + log.error("IP:{} 格式错误:{}", ip, e.getMessage()); + return ip; } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java index 6fe8fa91..1a7795da 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java @@ -13,14 +13,22 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.lakala.LklBanks; +import com.suisung.mall.common.utils.JiebaUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.lakala.mapper.LklBanksMapper; import com.suisung.mall.shop.lakala.service.LklBanksService; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.util.List; + +@Slf4j @Service public class LklBanksServiceImpl extends BaseServiceImpl implements LklBanksService { + @Resource + private JiebaUtils jiebaUtils; /** * 根据关键字查询有效记录分页列表 @@ -43,14 +51,24 @@ public class LklBanksServiceImpl extends BaseServiceImpl wrapper - .like("branch_bank_name", keyword) - .or() - .like("branch_bank_no", keyword) - .or() - .like("clear_no", keyword) - .or() - .like("bank_no", keyword)); + List keywordList = jiebaUtils.segmentForSearch(keyword); + log.info("分词后的关键词:{}", keywordList); + queryWrapper.and(wrapper -> { +// wrapper.like("branch_bank_name", keyword) +// .or() +// .like("branch_bank_no", keyword) +// .or() +// .like("clear_no", keyword) +// .or() +// .like("bank_no", keyword); + + // 再添加分词后的关键词条件 + + for (String kw : keywordList) { + wrapper.like("branch_bank_name", kw); + } + + }); } return lists(queryWrapper, pageNum, pageSize); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 8cc6e9ea..4846acd9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -131,7 +131,8 @@ public class LklTkServiceImpl { } catch (IllegalArgumentException e) { logger.error("Base64 解码时出现非法参数异常: ", e.getMessage()); } catch (Exception e) { - // 捕获其他可能的异常,如 NoSuchAlgorithmException、NoSuchPaddingException、InvalidKeySpecException、InvalidKeyException、BadPaddingException 等 + // 捕获其他可能的异常,如 NoSuchAlgorithmException、NoSuchPaddingException、 + // InvalidKeySpecException、InvalidKeyException、BadPaddingException 等 logger.error("解密过程中出现异常: ", e.getMessage()); } @@ -337,7 +338,7 @@ public class LklTkServiceImpl { header.put("Authorization", getLklTkAuthorization()); // 获取商家入驻信息,组成请求参数 - ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, bizLicenseNumber, CommonConstant.MCH_APPR_STA_LKL_PADDING); + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, bizLicenseNumber, CommonConstant.MCH_APPR_STA_PASS, CommonConstant.MCH_APPR_STA_LKL_PADDING); if (ObjectUtil.isEmpty(shopMchEntry)) { return Pair.of(false, "商家入驻信息不存在"); } @@ -425,12 +426,14 @@ public class LklTkServiceImpl { JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); bizContent.put("termNum", "1"); - bizContent.put("mcc", "5311"); // 超市的 code + bizContent.put("mcc", "12015"); // 超市的 code bizContent.put("fees", new JSONArray() {{ - put(new JSONObject() {{ - put("feeCode", "WECHAT"); - put("feeValue", 0.38); - }}); + put(new JSONObject() { + { + put("feeCode", "WECHAT"); + put("feeValue", 0.6); + } + }); }}); formData.put("bizContent", bizContent); @@ -526,17 +529,21 @@ public class LklTkServiceImpl { JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody); if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) { - return new JSONObject().set("code", "500").set("message", "参数格式有误"); + return new JSONObject().set("code", "500").set("message", "参数格式有误,无法解析"); + } + + String srcData = reqBodyJSON.getStr("data"); + if (StrUtil.isBlank(srcData)) { + return new JSONObject().set("code", "500").set("message", "关键参数为空值"); } // 公钥解密出来的数据 String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath); logger.debug("解密公钥:{}", notifyPubKey); - String data = decryptNotifyData(notifyPubKey, reqBodyJSON.getStr("data")); - logger.debug("拉卡拉进件异步通知返回解密后的参数:{}", data); - + String data = decryptNotifyData(notifyPubKey, srcData); + logger.debug("拉卡拉进件异步通知返回 data 数据:{}, 解密后的 data 数据:{}", srcData, data); if (StrUtil.isBlank(data)) { - return new JSONObject().set("code", "500").set("message", "参数解密出错"); + return new JSONObject().set("code", "500").set("message", "无法解密出 data 参数"); } // 逻辑处理 @@ -548,7 +555,6 @@ public class LklTkServiceImpl { // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 - ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); if (ObjectUtil.isEmpty(shopMchEntry)) { return new JSONObject().set("code", "500").set("message", "商户入驻信息不存在"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 0e74dacd..4cfcc46a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -103,10 +103,10 @@ public interface ShopMchEntryService { * * @param loginMobile * @param bizLicenseNumber - * @param approvalStatus + * @param approvalStatusList * @return */ - ShopMchEntry getShopMerchEntryByCondition(String loginMobile, String bizLicenseNumber, Integer approvalStatus); + ShopMchEntry getShopMerchEntryByCondition(String loginMobile, String bizLicenseNumber, Integer... approvalStatusList); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index ca14330d..9e13cc78 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -42,10 +42,7 @@ import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * 商家入驻申请表 @@ -634,12 +631,12 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return null; @@ -744,7 +740,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("login_mobile", loginMobile); if (ObjectUtil.isNotEmpty(lklAuditStatus)) { - updateWrapper.set("lkl_audit_status", lklAuditStatus); + updateWrapper.set("lkl_tk_audit_status", lklAuditStatus); } if (StrUtil.isNotBlank(lklMerCupNo)) { updateWrapper.set("lkl_mer_cup_no", lklMerCupNo); // 银联商户号 @@ -778,7 +774,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("lkl_mer_inner_no", lklInnerMerNo); if (ObjectUtil.isNotEmpty(lklAuditStatus)) { - updateWrapper.set("lkl_audit_status", lklAuditStatus); + updateWrapper.set("lkl_tk_audit_status", lklAuditStatus); } // 商家入驻审核正式通过 From d1c6630ef53f1265216822bc8bfdaf8ae55a9d76 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Wed, 14 May 2025 00:51:51 +0800 Subject: [PATCH 21/39] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8B=89=E5=8D=A1?= =?UTF-8?q?=E6=8B=89=E7=9A=84=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/store/ShopMchEntry.java | 3 + .../suisung/mall/common/utils/JiebaUtils.java | 4 +- .../controller/mobile/LklTkController.java | 9 + .../lakala/service/impl/LklTkServiceImpl.java | 163 +++++++++++++----- .../store/service/ShopMchEntryService.java | 17 +- .../service/impl/ShopMchEntryServiceImpl.java | 27 ++- .../lakala/prod/tk_notify_private_key.txt | 2 +- .../lakala/prod/tk_notify_public_key.txt | 2 +- 8 files changed, 165 insertions(+), 62 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 44600acc..d792a763 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -217,6 +217,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉进件请求参数") private String lkl_tk_reg_params; + @ApiModelProperty(value = "异步通知的请求参数(加密过)") + private String lkl_tk_reg_notify_req; + @ApiModelProperty(value = "拉卡拉进件成功返回的JSON数据") private String lkl_tk_reg_resp; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java index ba6c7760..531a3ad5 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java @@ -21,8 +21,8 @@ public class JiebaUtils { public static void main(String[] args) { JiebaUtils jiebaUtils = new JiebaUtils(); - String text = "中国工商银行桂平市光明支行"; - List words = jiebaUtils.segmentForSearch(text); + String text = "农行桂平"; + List words = jiebaUtils.segment(text); System.out.println(words); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index e5a31ae2..a9f5a577 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -37,6 +37,15 @@ public class LklTkController extends BaseControllerImpl { @Resource private LklBanksService lklBanksService; + @ApiOperation(value = "解密拉卡拉进件返回的异步通知", notes = "解密拉卡拉进件返回的异步通知") + @RequestMapping(value = "/decode", method = RequestMethod.POST) + public String decryptLklTkData(@RequestParam(name = "data") String data, + @RequestParam(name = "key") String key) { + + return lklTkService.decryptNotifyData(key, data); + + } + @ApiOperation(value = "搜索国内银行(支行)分页列表", notes = "搜索国内银行(支行)分页列表,数据包含有效的收款结清行号") @RequestMapping(value = "/bank/search", method = RequestMethod.POST) public CommonResult searchLklBanksPageList(@RequestBody JSONObject paramsJSON) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 4846acd9..10928ba9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -41,11 +41,16 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; -import java.security.KeyFactory; -import java.security.PublicKey; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import java.util.HashMap; @@ -70,9 +75,6 @@ public class LklTkServiceImpl { @Value("${lakala.tk.user_no}") private String userNo; - @Value("${lakala.org_code}") - private String orgCode; - @Value("${lakala.tk.notify_pub_key_path}") private String notifyPubKeyPath; @@ -102,6 +104,63 @@ public class LklTkServiceImpl { @Autowired private RedisService redisService; + /** + * 拉卡拉使用私钥加密数据 + */ + public static String encryptNotifyData(String priKey, String data) { + ByteArrayOutputStream out = null; + try { + // pubKey 去掉 空格、制表符(\t)、换行符(\n)、回车符(\r) + priKey = priKey.replaceAll("\\s+", ""); + + logger.debug("拉卡拉tk加密私钥:{}", priKey); + logger.debug("拉卡拉tk待加密data数据:{}", data); + + // 解码私钥 + byte[] keyBytes = Base64.getDecoder().decode(priKey); + + // 生成私钥对象 + PrivateKey privateKey = KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); + + // 初始化加密器 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + + // 分段加密 + byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); + out = new ByteArrayOutputStream(); + for (int offset = 0; offset < dataBytes.length; offset += 117) { + int blockSize = Math.min(117, dataBytes.length - offset); + byte[] encryptedBlock = cipher.doFinal(dataBytes, offset, blockSize); + out.write(encryptedBlock); + } + + // 编码为Base64字符串 + String encryptDataStr = Base64.getEncoder().encodeToString(out.toByteArray()); + + logger.debug("拉卡拉tk数据加密结果:{}", encryptDataStr); + return encryptDataStr; + } catch (Exception e) { + throw new RuntimeException("私钥加密失败", e); + } finally { + closeQuietly(out); + } + } + + /** + * 安全关闭流 + */ + private static void closeQuietly(ByteArrayOutputStream out) { + if (out != null) { + try { + out.close(); + } catch (Exception e) { + // 忽略异常 + } + } + } + /** * 拉卡拉异步通知数据公钥解密 * @@ -110,14 +169,19 @@ public class LklTkServiceImpl { * @return 解密字符串 */ public String decryptNotifyData(String pubKey, String data) { + ByteArrayOutputStream out = null; try { + logger.debug("拉卡拉tk解密公钥:{}", pubKey); + logger.debug("拉卡拉tk待解密data数据:{}", data); + // pubKey 去掉 空格、制表符(\t)、换行符(\n)、回车符(\r) + pubKey = pubKey.replaceAll("\\s+", ""); Base64.Decoder decoder = Base64.getDecoder(); - byte[] keyBytes = decoder.decode(pubKey.getBytes()); - byte[] dataBytes = decoder.decode(data.getBytes()); + byte[] keyBytes = decoder.decode(pubKey.getBytes(StandardCharsets.UTF_8)); + byte[] dataBytes = decoder.decode(data.getBytes(StandardCharsets.UTF_8)); Cipher cipher = Cipher.getInstance("RSA"); PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes)); cipher.init(Cipher.DECRYPT_MODE, publicKey); - ByteArrayOutputStream out = new ByteArrayOutputStream(); + out = new ByteArrayOutputStream(); byte[] cache; for (int i = 0, offset = 0, length = dataBytes.length; length - offset > 0; i++, offset = i * 128) { if (length - offset > 128) { @@ -127,13 +191,23 @@ public class LklTkServiceImpl { } out.write(cache, 0, cache.length); } - return out.toString(); + + String decodedDataStr = out.toString("UTF-8"); + logger.debug("拉卡拉tk数据解密结果:{}", decodedDataStr); + + return decodedDataStr; } catch (IllegalArgumentException e) { - logger.error("Base64 解码时出现非法参数异常: ", e.getMessage()); + logger.error("Base64解码失败: {}", e.getMessage(), e); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + logger.error("RSA算法初始化失败: {}", e.getMessage(), e); + } catch (InvalidKeySpecException | InvalidKeyException e) { + logger.error("私钥格式或类型错误: {}", e.getMessage(), e); + } catch (BadPaddingException | IllegalBlockSizeException e) { + logger.error("解密数据块大小或填充错误: {}", e.getMessage(), e); } catch (Exception e) { - // 捕获其他可能的异常,如 NoSuchAlgorithmException、NoSuchPaddingException、 - // InvalidKeySpecException、InvalidKeyException、BadPaddingException 等 - logger.error("解密过程中出现异常: ", e.getMessage()); + logger.error("解密过程中出现未知异常: {}", e.getMessage(), e); + } finally { + closeQuietly(out); } return null; @@ -400,7 +474,6 @@ public class LklTkServiceImpl { formData.put("settleType", "D1"); //结算类型,D0秒到,D1次日结算 // formData.put("settlementType", "AUTOMATIC"); // 结算方式:MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持) - // 店铺省市区信息 Map areaCode = getAreaCode(shopMchEntry.getStore_area(), false); if (ObjectUtil.isNotEmpty(areaCode)) { @@ -422,7 +495,7 @@ public class LklTkServiceImpl { } - // TODO 咨询拉卡拉清楚 + // 费率和设备、活动 JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); bizContent.put("termNum", "1"); @@ -439,24 +512,26 @@ public class LklTkServiceImpl { // 附件文件相关开始 JSONArray attachments = new JSONArray(); - JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", false); - if (ID_CARD_FRONT != null) { - attachments.put(ID_CARD_FRONT); // 身份证正面 - } + if (isQy) { + JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "FR_ID_CARD_FRONT", false); + if (SETTLE_ID_CARD_FRONT != null) { + attachments.put(SETTLE_ID_CARD_FRONT); // 法人身份证正面 + } - JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", false); - if (ID_CARD_BEHIND != null) { - attachments.put(ID_CARD_BEHIND); // 身份证国徽面 - } + JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "FR_ID_CARD_BEHIND", false); + if (SETTLE_ID_CARD_BEHIND != null) { + attachments.put(SETTLE_ID_CARD_BEHIND); // 法人身份证国徽面 + } + } else { + JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", false); + if (ID_CARD_FRONT != null) { + attachments.put(ID_CARD_FRONT); // 身份证正面 + } - JSONObject SETTLE_ID_CARD_FRONT = updatePhoto(shopMchEntry.getLegal_person_id_images(), "FR_ID_CARD_FRONT", false); - if (SETTLE_ID_CARD_FRONT != null) { - attachments.put(SETTLE_ID_CARD_FRONT); // 法人身份证正面 - } - - JSONObject SETTLE_ID_CARD_BEHIND = updatePhoto(shopMchEntry.getLegal_person_id_images2(), "FR_ID_CARD_BEHIND", false); - if (SETTLE_ID_CARD_BEHIND != null) { - attachments.put(SETTLE_ID_CARD_BEHIND); // 法人身份证国徽面 + JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", false); + if (ID_CARD_BEHIND != null) { + attachments.put(ID_CARD_BEHIND); // 身份证国徽面 + } } JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", false); @@ -486,18 +561,20 @@ public class LklTkServiceImpl { logger.info("进件请求参数:{}", JSONUtil.toJsonStr(formData)); ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); - if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - String errMsg = "进件返回空或请求状态异常"; - if (ObjectUtil.isNotEmpty(response.getBody()) && ObjectUtil.isNotEmpty(response.getBody().getStr("message"))) { - errMsg = response.getBody().getStr("message"); - } + if (ObjectUtil.isEmpty(response)) { + return Pair.of(false, "进件失败:进件无返回值"); + } + + JSONObject respBody = response.getBody(); + if (response.getStatusCode() != HttpStatus.OK && ObjectUtil.isNotEmpty(respBody)) { + String errMsg = respBody.getStr("message") == null ? "返回状态有误" : respBody.getStr("message"); return Pair.of(false, "进件失败:" + errMsg); } // 更改入驻记录的拉卡拉内部商户号和进件请求参数 - String lklMerCupNo = response.getBody().getStr("merchantNo"); //拉卡拉内部商户号 + String lklMerCupNo = respBody.getStr("merchantNo"); //拉卡拉内部商户号 // 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录 - Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerCupNo, lklMerCupNo, formData.toString()); + Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerCupNo, lklMerCupNo, formData.toString(), respBody.toString()); if (!success) { return Pair.of(false, "提交进件成功,但更新商户号失败!"); } @@ -518,7 +595,6 @@ public class LklTkServiceImpl { */ public JSONObject registrationMerchantNotify(HttpServletRequest request) { logger.debug("拉卡拉进件异步通知开始"); - JSONObject respData = new JSONObject(); // 解密请求参数 String requestBody = LakalaUtil.getBody(request); @@ -539,13 +615,13 @@ public class LklTkServiceImpl { // 公钥解密出来的数据 String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath); - logger.debug("解密公钥:{}", notifyPubKey); String data = decryptNotifyData(notifyPubKey, srcData); - logger.debug("拉卡拉进件异步通知返回 data 数据:{}, 解密后的 data 数据:{}", srcData, data); if (StrUtil.isBlank(data)) { - return new JSONObject().set("code", "500").set("message", "无法解密出 data 参数"); + return new JSONObject().set("code", "500").set("message", "密文解密出错!"); } + logger.debug("拉卡拉进件异步通知data解密成功,开始处理逻辑"); + // 逻辑处理 JSONObject dataJSON = JSONUtil.parseObj(data); if (dataJSON.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo"))) { @@ -557,7 +633,8 @@ public class LklTkServiceImpl { String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); if (ObjectUtil.isEmpty(shopMchEntry)) { - return new JSONObject().set("code", "500").set("message", "商户入驻信息不存在"); + logger.error("拉卡拉进件异步通知:返回的外部商户号:{} 入驻信息不存在!", merCupNo); + return new JSONObject().set("code", "500").set("message", "外部商户号:" + merCupNo + " 入驻信息不存在"); } Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, data); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 4cfcc46a..b672f8eb 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -139,22 +139,23 @@ public interface ShopMchEntryService { /** * 更新商家入驻申请的拉卡拉商户号 * - * @param loginMobile - * @param lklAuditStatus + * @param loginMobile 商家注册的手机号 + * @param lklAuditStatus 拉卡拉审核状态 * @param lklMerCupNo 拉卡拉银联商户号 * @param lklMerInnerNo 拉卡拉内部商户号 - * @param lklTkRegParams + * @param lklTkRegParams 进件请求参数 + * @param lklTkRegResp 进件返回的数据 * @return */ - Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklMerInnerNo, String lklTkRegParams); + Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklMerInnerNo, String lklTkRegParams, String lklTkRegResp); /** * 更新商家入驻申请的拉卡拉审核状态和响应数据 * - * @param lklMerCupNo - * @param lklInnerMerNo - * @param lklAuditStatus - * @param lklTkRegResp + * @param lklMerCupNo 拉卡拉银联商户号 + * @param lklInnerMerNo 拉卡拉内部商户号 + * @param lklAuditStatus 拉卡拉审核状态 + * @param lklTkRegResp 进件返回的数据 * @return */ Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, String lklTkRegResp); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 9e13cc78..10d484ba 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -411,6 +411,10 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("mer_cup_no", merCupNo).eq("status", CommonConstant.Enable).orderByAsc("id"); + queryWrapper.eq("lkl_mer_cup_no", merCupNo).eq("status", CommonConstant.Enable).orderByAsc("id"); List recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { return null; @@ -732,7 +736,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl Date: Wed, 14 May 2025 16:13:54 +0800 Subject: [PATCH 22/39] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=E8=81=94?= =?UTF-8?q?=E8=B0=83=20bug=20=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/EsignController.java | 6 +++- .../service/EsignPlatformInfoService.java | 2 +- .../impl/EsignContractServiceImpl.java | 4 +-- .../impl/EsignPlatformInfoServiceImpl.java | 34 ++++++++++++++----- .../impl/LklLedgerReceiverServiceImpl.java | 6 ++-- .../lakala/service/impl/LklTkServiceImpl.java | 24 ++++++------- .../mall/shop/lakala/utils/LakalaUtil.java | 14 +++++--- .../store/service/ShopMchEntryService.java | 8 +++++ .../service/impl/ShopMchEntryServiceImpl.java | 16 +++++++++ 9 files changed, 79 insertions(+), 35 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java index 222412c1..e71b6a37 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java @@ -13,6 +13,7 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; +import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.http.ResponseEntity; @@ -36,11 +37,14 @@ public class EsignController extends BaseControllerImpl { @Resource private EsignContractService esignContractService; + @Resource + private EsignPlatformInfoService esignPlatformInfoService; + @ApiOperation(value = "测试填充模版控件", notes = "测试填充模版控件") @RequestMapping(value = "/testcase", method = RequestMethod.POST) public Object testCase() { //return esignContractFillingFileService.fillDocTemplate("13128997057", "91450881MADEQ92533"); - return esignContractService.getSignedContractFileUrl("27e8dad5491d4d9ab4bc6f8154ae8ff5"); + return esignPlatformInfoService.getDistributorAndPlatformByIds(1L); } @ApiOperation(value = "管理员发起签署电子合同流程", notes = "基于文件发起签署电子合同") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java index fcd69b67..80582157 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignPlatformInfoService.java @@ -32,7 +32,7 @@ public interface EsignPlatformInfoService { * @param ids * @return */ - List getDistributorInfoByIds(Long... ids); + List getDistributorAndPlatformByIds(Long... ids); /** * 根据分类和营业执照号获取平台方信息 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index de4743dd..d3abac9a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -220,8 +220,8 @@ public class EsignContractServiceImpl extends BaseServiceImpl list = getDistributorInfoByIds(id); - if (CollectionUtil.isEmpty(list)) { + if (id == null || id <= 0) { return null; } - return list.get(0); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("id", id) + .gt("level", 0) + .eq("status", CommonConstant.Enable).orderByAsc("level"); + + List esignPlatformInfos = list(queryWrapper); + if (CollectionUtil.isEmpty(esignPlatformInfos)) { + return null; + } + + return esignPlatformInfos.get(0); } /** - * 根据ID获取代理商信息 + * 根据一个或多个代理商自增ID获取代理商和平台记录,无论怎么都要获取一条平台方的记录 * * @param ids * @return */ @Override - public List getDistributorInfoByIds(Long... ids) { - if (ids == null || ids.length == 0) { - return null; + public List getDistributorAndPlatformByIds(Long... ids) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("status", CommonConstant.Enable).orderByAsc("level"); + if (ids != null && ids.length > 0) { + queryWrapper.and(wrapper -> { + wrapper.in("id", ids).gt("level", 0); + wrapper.or(wrapperOr -> { + wrapperOr.eq("level", 0); + }); + }); + } else { + queryWrapper.eq("level", 0); } - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.in("id", ids).eq("status", CommonConstant.Enable); List esignPlatformInfos = list(queryWrapper); if (CollectionUtil.isEmpty(esignPlatformInfos)) { return null; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 06672786..ab9d14c2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -135,11 +135,10 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl ids = new ArrayList<>(); - ids.add(0L); - if (ObjectUtil.isNotEmpty(platformId)) { + if (platformId != null && platformId > 0) { ids.add(platformId); } - List esignPlatformInfoList = esignPlatformInfoService.getDistributorInfoByIds(ids.toArray(new Long[0])); + List esignPlatformInfoList = esignPlatformInfoService.getDistributorAndPlatformByIds(ids.toArray(new Long[0])); if (CollectionUtil.isEmpty(esignPlatformInfoList)) { return null; } @@ -167,6 +166,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("lkl_mer_inner_no", merInnerNo).eq("status", CommonConstant.Enable).orderByAsc("id"); + List recordList = list(queryWrapper); + if (CollectionUtil.isEmpty(recordList)) { + return null; + } + + return recordList.get(0); + } + /** * 根据商家注册的手机号,更新合同签署状态和合同下载地址 * From 40beddaaa5594980940f1067c1fcab40b9729d51 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Wed, 14 May 2025 23:49:03 +0800 Subject: [PATCH 23/39] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=20=E5=85=A5?= =?UTF-8?q?=E7=BD=91=E7=94=B5=E5=AD=90=E5=90=88=E5=90=8C=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/lakala/LklLedgerEc.java | 47 ++++++ .../modules/lakala/LklLedgerMember.java | 5 + .../lakala/LklLedgerMerReceiverBind.java | 5 + .../modules/lakala/LklLedgerReceiver.java | 5 + .../controller/mobile/LakalaController.java | 9 +- .../shop/lakala/mapper/LklLedgerEcMapper.java | 18 ++ .../shop/lakala/service/LakalaApiService.java | 8 + .../lakala/service/LklLedgerEcService.java | 50 ++++++ .../service/impl/LakalaApiServiceImpl.java | 101 ++++++++++++ .../service/impl/LklLedgerEcServiceImpl.java | 154 ++++++++++++++++++ .../mapper/lakala/LklLedgerEcMapper.xml | 8 + 11 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerEcMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklLedgerEcMapper.xml diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java new file mode 100644 index 00000000..6347f1f4 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.lakala; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("lkl_ledger_ec") +@ApiModel(value = "拉卡拉商家入网电子合同申请表", description = "拉卡拉商家入网电子合同申请表") +public class LklLedgerEc implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") + private Long id; + private Long mch_id; + private String mch_mobile; + private String req_params; + private String resp_body; + private String resp_notify_body; + private String ec_no; + private String ec_name; + private String ec_status; + private Long ec_apply_id; + private String result_url; + private Integer status; + private Date created_at; + private Date updated_at; +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java index 03188643..ab48a72f 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java @@ -8,8 +8,11 @@ package com.suisung.mall.common.modules.lakala; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -25,6 +28,8 @@ import java.util.Date; public class LklLedgerMember implements Serializable { private static final long serialVersionUID = 1L; + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") private Long id; private String order_no; private String org_code; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java index f3525525..5b714f5e 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMerReceiverBind.java @@ -8,8 +8,11 @@ package com.suisung.mall.common.modules.lakala; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -25,6 +28,8 @@ import java.util.Date; public class LklLedgerMerReceiverBind implements Serializable { private static final long serialVersionUID = 1L; + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") private Long id; private String order_no; private String org_code; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java index 43ffbb9e..1c13fce2 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerReceiver.java @@ -8,8 +8,11 @@ package com.suisung.mall.common.modules.lakala; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -25,6 +28,8 @@ import java.util.Date; public class LklLedgerReceiver implements Serializable { private static final long serialVersionUID = 1L; + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") private Long id; private String order_no; private String org_id; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 871c08f4..10789daf 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -43,14 +43,19 @@ public class LakalaController extends BaseControllerImpl { return lakalaPayService.getBankCardBin(paramsJSON.getStr("bankCardNo")); } + @ApiOperation(value = "商户入网电子合同申请回调通知", notes = "商户入网电子合同申请回调通知") + @RequestMapping(value = "/ec/applyNotify", method = RequestMethod.POST) + public JSONObject ecApplyNotify(HttpServletRequest request) { + return lakalaPayService.applyLedgerMerNotify(request); + } + @ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请") @RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST) public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) { return lakalaPayService.applyLedgerMer(paramsJSON); } - - @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调") + @ApiOperation(value = "商户分账业务开通申请异步回调通知", notes = "商户分账业务开通申请异步回调通知") @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) { return lakalaPayService.applyLedgerMerNotify(request); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerEcMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerEcMapper.java new file mode 100644 index 00000000..58542aba --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklLedgerEcMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklLedgerEc; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklLedgerEcMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 3c7fc470..63f81207 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -90,6 +90,14 @@ public interface LakalaApiService { */ JSONObject uploadFile(String orderNo, String attType, String attExtName, String attContext); + /** + * 商家申请入网电子合同 + * + * @param mchMobile + * @return + */ + Pair applyLedgerMerEc(String mchMobile); + /** * 商户分账业务开通申请 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java new file mode 100644 index 00000000..5d8a82b0 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.modules.lakala.LklLedgerEc; +import com.suisung.mall.core.web.service.IBaseService; + +public interface LklLedgerEcService extends IBaseService { + + /** + * 根据商家Id新增或更新记录 + * + * @param record + * @return + */ + Boolean saveOrUpdateByMchId(LklLedgerEc record); + + /** + * 根据applyId更新记录 + * + * @param record + * @return + */ + Boolean updateByApplyId(LklLedgerEc record); + + /** + * 根据接applyId查询记录 + * + * @param applyId + * @return + */ + LklLedgerEc getByApplyId(Long applyId); + + + /** + * 通过mchId商家Id记录信息构建申请入网电子合同的请求参数 + * + * @param mchMobile + * @return + */ + JSONObject buildApplyLedgerEcReqParams(String mchMobile); + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index cd8b6b78..468dba31 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -52,6 +52,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -449,6 +450,106 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } + /** + * 商家申请入网电子合同 + * + * @param mchMobile + * @return + */ + @Override + public Pair applyLedgerMerEc(String mchMobile) { + log.debug("商家开始申请入网电子合同"); + if (StrUtil.isBlank(mchMobile)) { + return Pair.of(false, I18nUtil._("缺少商家必要参数!")); + } + + // 获取商家信息 + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, ""); + if (shopMchEntry == null) { + return Pair.of(false, I18nUtil._("无法查找商家相关信息!")); + } + + // 是企业类型商家 + Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()); + + JSONObject reqData = new JSONObject(); + reqData.put("order_no", StringUtils.genLklOrderNo(8)); + reqData.put("org_id", orgCode); + reqData.put("ec_type_code", "EC007"); + reqData.put("cert_type", "RESIDENT_ID"); + + String larName = isQy ? shopMchEntry.getLegal_person_name() : shopMchEntry.getContact_name(); + String larIdCard = isQy ? shopMchEntry.getLegal_person_id_number() : shopMchEntry.getIndividual_id_number(); + reqData.put("cert_name", larName); + reqData.put("cert_no", larIdCard); + reqData.put("mobile", shopMchEntry.getLogin_mobile()); + + if (isQy) { + reqData.put("business_license_no", shopMchEntry.getBiz_license_number()); + reqData.put("business_license_name", shopMchEntry.getBiz_license_company()); + } + reqData.put("openning_bank_code", shopMchEntry.getOpenning_bank_code()); + reqData.put("openning_bank_name", shopMchEntry.getBank_name()); + reqData.put("acct_type_code", shopMchEntry.getAccount_type());//57 对公、 58 对私 + reqData.put("acct_no", shopMchEntry.getAccount_number()); + reqData.put("acct_name", shopMchEntry.getAccount_holder_name()); + + String domain = projectDomain; + if (isProd()) { + domain += "/api"; + } + // 给拉卡拉通知的回调地址 + String retUrl = domain + "/mobile/shop/lakala/ec/applyNotify"; + reqData.put("ret_url", retUrl); + + LocalDate today = LocalDate.now(); // 获取当前日期 + String signDate = today.getYear() + "-" + today.getMonthValue() + "-" + today.getDayOfMonth(); + + JSONObject ecParams = new JSONObject(); + ecParams.put("A1", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); + ecParams.put("A30", "0.6"); // 测试环境微信费率0.6 + ecParams.put("A96", "D1"); + ecParams.put("A97", "开通"); + ecParams.put("A100", "不开通"); + ecParams.put("A101", "中国境内"); + ecParams.put("A104", today.getYear()); + ecParams.put("A105", today.getMonthValue()); + ecParams.put("A106", today.getDayOfMonth()); + ecParams.put("A107", today.getYear()); + ecParams.put("A108", today.getMonthValue()); + ecParams.put("A109", today.getDayOfMonth()); + ecParams.put("B1", today.getYear()); + ecParams.put("B2", today.getMonthValue()); + ecParams.put("B8", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); + ecParams.put("B9", shopMchEntry.getSales_info()); + ecParams.put("B10", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); + ecParams.put("B14", isQy ? shopMchEntry.getBiz_license_number() : ""); + ecParams.put("B19", shopMchEntry.getOpenning_bank_code()); + ecParams.put("B20", shopMchEntry.getAccount_number()); + ecParams.put("B31", shopMchEntry.getStore_name()); + ecParams.put("B32", shopMchEntry.getContact_name()); + ecParams.put("B33", shopMchEntry.getStore_address()); + ecParams.put("B34", shopMchEntry.getLogin_mobile()); + ecParams.put("D1", shopMchEntry.getBank_name()); + ecParams.put("D2", signDate); + ecParams.put("D4", "桂平发发网络有限公司"); + ecParams.put("D7", signDate); + ecParams.put("D9", signDate); + ecParams.put("D11", signDate); + ecParams.put("D12", signDate); + ecParams.put("E1", "桂平发发网络有限公司"); + ecParams.put("E2", "平台商户入驻合同协议"); + ecParams.put("E3", "0"); + ecParams.put("E4", "70"); + ecParams.put("E5", "桂平发发网络有限公司"); + ecParams.put("E7", signDate); + ecParams.put("E8", shopMchEntry.getAccount_holder_name()); + + reqData.put("ec_content_parameters", ecParams); + + return null; + } + /** * 商户分账业务开通申请 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java new file mode 100644 index 00000000..3572c05a --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.modules.lakala.LklLedgerEc; +import com.suisung.mall.common.modules.store.ShopMchEntry; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; +import com.suisung.mall.shop.lakala.mapper.LklLedgerEcMapper; +import com.suisung.mall.shop.lakala.service.LakalaApiService; +import com.suisung.mall.shop.lakala.service.LklLedgerEcService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +@Service +public class LklLedgerEcServiceImpl extends BaseServiceImpl implements LklLedgerEcService { + + + @Resource + private EsignPlatformInfoService esignPlatformInfoService; + + @Lazy + @Resource + private LakalaApiService lakalaApiService; + + @Lazy + @Resource + private ShopMchEntryService shopMchEntryService; + + /** + * 根据商家Id新增或更新记录 + * + * @param record + * @return + */ + @Override + public Boolean saveOrUpdateByMchId(LklLedgerEc record) { + if (record == null || (ObjectUtil.isEmpty(record.getMch_id()) && StrUtil.isBlank(record.getMch_mobile()))) { + return false; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (ObjectUtil.isEmpty(record.getMch_id())) { + queryWrapper.eq("mch_id", record.getMch_id()); + } + if (ObjectUtil.isEmpty(record.getMch_mobile())) { + queryWrapper.eq("mch_mobile", record.getMch_mobile()); + } + + List existsRecordList = list(queryWrapper); + if (CollectionUtil.isNotEmpty(existsRecordList) + && existsRecordList.get(0) != null + && existsRecordList.get(0).getId() > 0) { + // 更新记录 + record.setId(existsRecordList.get(0).getId()); + return updateById(record); + } + + return add(record); + } + + + /** + * 根据applyId更新记录 + * + * @param record + * @return + */ + @Override + public Boolean updateByApplyId(LklLedgerEc record) { + if (record == null || ObjectUtil.isEmpty(record.getEc_apply_id())) { + return false; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("ec_apply_id", record.getEc_apply_id()); + + LklLedgerEc existsRecord = getOne(queryWrapper); + if (existsRecord == null) { + return false; + } + + // 更新记录 + record.setId(existsRecord.getId()); + return updateById(record); + } + + /** + * 根据接applyId查询记录 + * + * @param applyId + * @return + */ + @Override + public LklLedgerEc getByApplyId(Long applyId) { + if (ObjectUtil.isEmpty(applyId)) { + return null; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("ec_apply_id", applyId); + + return getOne(queryWrapper); + } + + /** + * 通过mchId商家Id记录信息构建申请入网电子合同的请求参数 + * + * @param mchMobile + * @return + */ + @Override + public JSONObject buildApplyLedgerEcReqParams(String mchMobile) { + if (StrUtil.isBlank(mchMobile)) { + return null; + } + + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, ""); + if (shopMchEntry == null) { + return null; + } + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + jsonObject.put("mch_id", shopMchEntry.getId()); + + + return jsonObject; + } +} diff --git a/mall-shop/src/main/resources/mapper/lakala/LklLedgerEcMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklLedgerEcMapper.xml new file mode 100644 index 00000000..0e99c16e --- /dev/null +++ b/mall-shop/src/main/resources/mapper/lakala/LklLedgerEcMapper.xml @@ -0,0 +1,8 @@ + + + + + + * + + From 8eb9cf3ce6499a5486a38e3dfe7bb8b0a4b66955 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Thu, 15 May 2025 15:53:29 +0800 Subject: [PATCH 24/39] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=20=E5=85=A5?= =?UTF-8?q?=E7=BD=91=E7=94=B5=E5=AD=90=E5=90=88=E5=90=8C=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E5=8A=A0=E5=AF=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/lakala/LklLedgerEc.java | 1 + .../suisung/mall/common/utils/JiebaUtils.java | 3 + .../suisung/mall/common/utils/RSAUtil.java | 159 +++++++++++++++ .../suisung/mall/pay/utils/LakalaUtil.java | 14 +- .../impl/EsignContractServiceImpl.java | 11 +- .../controller/mobile/LakalaController.java | 6 + .../controller/mobile/LklTkController.java | 3 +- .../service/impl/LakalaApiServiceImpl.java | 76 ++++++- .../impl/LklLedgerReceiverServiceImpl.java | 5 + .../lakala/service/impl/LklTkServiceImpl.java | 117 +---------- .../mall/shop/lakala/utils/LakalaUtil.java | 188 ++++++++++++++++-- .../src/main/resources/bootstrap-dev.yml | 2 +- .../src/main/resources/bootstrap-local.yml | 4 +- .../src/main/resources/bootstrap-prod.yml | 2 +- .../src/main/resources/bootstrap-test.yml | 2 +- .../src/main/resources/bootstrap-uat.yml | 2 +- 16 files changed, 439 insertions(+), 156 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java index 6347f1f4..3aa80583 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java @@ -41,6 +41,7 @@ public class LklLedgerEc implements Serializable { private String ec_status; private Long ec_apply_id; private String result_url; + private String notify_url; private Integer status; private Date created_at; private Date updated_at; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java index 531a3ad5..6308bca5 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/JiebaUtils.java @@ -14,6 +14,9 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.stream.Collectors; +/** + * 结巴分词工具类 + */ @Component public class JiebaUtils { diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java new file mode 100644 index 00000000..ff063c95 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class RSAUtil { + + private static final Logger logger = LoggerFactory.getLogger(RSAUtil.class); + + /** + * 使用私钥对数据进行 SHA256withRSA 签名 + * + * @param data 待签名的数据 + * @param privateKey 私钥(Base64编码) + * @return 签名结果(Base64编码) + */ + public static String signSHA256withRSA(String data, String privateKey) { + try { + // 解码私钥 + byte[] keyBytes = Base64.getDecoder().decode(privateKey); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + + // 生成私钥对象 + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey priKey = keyFactory.generatePrivate(keySpec); + + // 初始化签名 + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(priKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + + // 生成签名并编码为Base64 + byte[] signBytes = signature.sign(); + return Base64.getEncoder().encodeToString(signBytes); + } catch (NoSuchAlgorithmException e) { + logger.error("不支持的加密算法: {}", e.getMessage(), e); + } catch (InvalidKeySpecException e) { + logger.error("私钥格式错误: {}", e.getMessage(), e); + } catch (InvalidKeyException e) { + logger.error("无效的私钥: {}", e.getMessage(), e); + } catch (SignatureException e) { + logger.error("签名处理异常: {}", e.getMessage(), e); + } catch (Exception e) { + logger.error("签名过程发生未知异常: {}", e.getMessage(), e); + } + return null; + } + + /** + * 使用公钥验证 SHA256withRSA 签名 + * + * @param data 原始数据 + * @param sign 签名结果(Base64编码) + * @param publicKey 公钥(Base64编码) + * @return 验证结果 + */ + public static boolean verifySHA256withRSA(String data, String sign, String publicKey) { + try { + // 解码公钥 + byte[] keyBytes = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + + // 生成公钥对象 + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey pubKey = keyFactory.generatePublic(keySpec); + + // 初始化签名验证 + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initVerify(pubKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + + // 验证签名 + byte[] signBytes = Base64.getDecoder().decode(sign); + return signature.verify(signBytes); + } catch (NoSuchAlgorithmException e) { + logger.error("不支持的加密算法: {}", e.getMessage(), e); + } catch (InvalidKeySpecException e) { + logger.error("公钥格式错误: {}", e.getMessage(), e); + } catch (InvalidKeyException e) { + logger.error("无效的公钥: {}", e.getMessage(), e); + } catch (SignatureException e) { + logger.error("签名验证异常: {}", e.getMessage(), e); + } catch (Exception e) { + logger.error("验证过程发生未知异常: {}", e.getMessage(), e); + } + return false; + } + + /** + * 生成 RSA 密钥对 + * + * @param keySize 密钥长度,推荐 2048 + * @return 密钥对 + */ + public static KeyPair generateKeyPair(int keySize) { + KeyPairGenerator keyPairGen = null; + try { + keyPairGen = KeyPairGenerator.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + keyPairGen.initialize(keySize); + return keyPairGen.generateKeyPair(); + } + + /** + * 获取公钥的 Base64 编码字符串 + */ + public static String getPublicKeyString(KeyPair keyPair) { + PublicKey publicKey = keyPair.getPublic(); + return Base64.getEncoder().encodeToString(publicKey.getEncoded()); + } + + /** + * 获取私钥的 Base64 编码字符串 + */ + public static String getPrivateKeyString(KeyPair keyPair) { + PrivateKey privateKey = keyPair.getPrivate(); + return Base64.getEncoder().encodeToString(privateKey.getEncoded()); + } + + // 示例用法 + public static void main(String[] args) { + try { + // 生成密钥对 + KeyPair keyPair = generateKeyPair(2048); + String publicKey = getPublicKeyString(keyPair); + String privateKey = getPrivateKeyString(keyPair); + + // 待签名数据 + String data = "Hello, RSA Signature!"; + + // 签名 + String signature = signSHA256withRSA(data, privateKey); + System.out.println("签名结果: " + signature); + + // 验证 + boolean isValid = verifySHA256withRSA(data, signature, publicKey); + System.out.println("验证结果: " + isValid); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java index 0347ebb3..00ffa9d7 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java @@ -11,7 +11,6 @@ package com.suisung.mall.pay.utils; import cn.hutool.core.util.StrUtil; import com.lkl.laop.sdk.Config2; import com.lkl.laop.sdk.LKLSDK; -import com.lkl.laop.sdk.auth.PrivateKeySigner; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.utils.I18nUtil; import lombok.extern.slf4j.Slf4j; @@ -76,6 +75,7 @@ public class LakalaUtil { } } + /** * 获取 body 请求数据 * @@ -130,7 +130,6 @@ public class LakalaUtil { } } - /** * 签名验证 * @@ -155,9 +154,9 @@ public class LakalaUtil { } } - /** * 签名校验 + * * @param authorization * @param reqBody * @param lklNotifyCerPath @@ -176,11 +175,9 @@ public class LakalaUtil { return false; } - StringBuilder preSignData = new StringBuilder(); - preSignData.append(timestamp).append("\n") - .append(nonceStr).append("\n") - .append(reqBody).append("\n"); - String preSignDataStr = preSignData.toString(); + String preSignDataStr = timestamp + "\n" + + nonceStr + "\n" + + reqBody + "\n"; log.debug("拉卡拉签名明文内容:{}", preSignDataStr); if (verify(lklNotifyCer, preSignDataStr.getBytes(StandardCharsets.UTF_8), signature)) { log.debug("验签成功"); @@ -237,4 +234,5 @@ public class LakalaUtil { return map; } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index d3abac9a..03c51055 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -211,9 +211,14 @@ public class EsignContractServiceImpl extends BaseServiceImpl response = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class); + if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { + return Pair.of(false, "商家入网申请电子合同:请求失败"); + } + + JSONObject respBody = response.getBody(); + if (ObjectUtil.isNotEmpty(respBody) && !lklSuccessCode.equals(respBody.getStr("code"))) { + String errMsg = StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg"); + return Pair.of(false, "商家入网申请电子合同失败:" + errMsg); + } + + JSONObject respData = respBody.getJSONObject("resp_data"); + if (respBody.getJSONObject("resp_data") == null) { + return Pair.of(false, "商家入网申请电子合同失败:返回数据有误"); + } + + // 商家入网申请电子合同处理数据 + // 先写入本地数据库表中 + LklLedgerEc record = new LklLedgerEc(); + record.setMch_id(shopMchEntry.getId()); + record.setMch_mobile(shopMchEntry.getLogin_mobile()); + record.setReq_params(reqBody.toString()); + record.setNotify_url(retUrl); + record.setEc_apply_id(respData.getLong("ec_apply_id")); + record.setResult_url(respData.getStr("result_url")); + record.setResp_body(respBody.toString()); + Boolean success = lklLedgerEcService.saveOrUpdateByMchId(record); + if (!success) { + return Pair.of(false, "商家入网申请电子合同失败:本地数据保存失败"); + } + + + return Pair.of(true, "商家入网申请电子合同成功"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index ab9d14c2..59720908 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -24,6 +24,7 @@ import com.suisung.mall.shop.lakala.mapper.LklLedgerReceiverMapper; import com.suisung.mall.shop.lakala.service.LakalaApiService; import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -31,6 +32,7 @@ import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; +@Slf4j @Service public class LklLedgerReceiverServiceImpl extends BaseServiceImpl implements LklLedgerReceiverService { @@ -207,13 +209,16 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl 0; i++, offset = i * 128) { - if (length - offset > 128) { - cache = cipher.doFinal(dataBytes, offset, 128); - } else { - cache = cipher.doFinal(dataBytes, offset, length - offset); - } - out.write(cache, 0, cache.length); - } - - String decodedDataStr = out.toString("UTF-8"); - logger.debug("拉卡拉tk数据解密结果:{}", decodedDataStr); - - return decodedDataStr; - } catch (IllegalArgumentException e) { - logger.error("Base64解码失败: {}", e.getMessage(), e); - } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - logger.error("RSA算法初始化失败: {}", e.getMessage(), e); - } catch (InvalidKeySpecException | InvalidKeyException e) { - logger.error("私钥格式或类型错误: {}", e.getMessage(), e); - } catch (BadPaddingException | IllegalBlockSizeException e) { - logger.error("解密数据块大小或填充错误: {}", e.getMessage(), e); - } catch (Exception e) { - logger.error("解密过程中出现未知异常: {}", e.getMessage(), e); - } finally { - closeQuietly(out); - } - - return null; - } protected String buildLklTkUrl(String urlPath) { return tkServerUrl + urlPath; @@ -610,8 +497,8 @@ public class LklTkServiceImpl { } // 公钥解密出来的数据 - String notifyPubKey = LakalaUtil.getResourceFileWithEndSeq(notifyPubKeyPath, false); - String data = decryptNotifyData(notifyPubKey, srcData); + String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false); + String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData); if (StrUtil.isBlank(data)) { return new JSONObject().set("code", "500").set("message", "密文解密出错!"); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java index d9cbb2a3..1f9e943d 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/utils/LakalaUtil.java @@ -13,23 +13,28 @@ import com.lkl.laop.sdk.Config2; import com.lkl.laop.sdk.LKLSDK; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.utils.I18nUtil; +import com.suisung.mall.common.utils.RSAUtil; +import com.suisung.mall.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.core.io.ClassPathResource; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import javax.servlet.http.HttpServletRequest; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.Signature; -import java.security.SignatureException; +import java.security.*; import java.security.cert.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @Slf4j public class LakalaUtil { @@ -58,10 +63,17 @@ public class LakalaUtil { * @return */ public static String getResourceFile(String fileName) { - return getResourceFileWithEndSeq(fileName, true); + return getResourceFile(fileName, true, false); } - public static String getResourceFileWithEndSeq(String fileName, boolean keepLineBreaks) { + /** + * 获取配置文件内容 + * + * @param fileName recource 文件夹下的路径,如:palyKey/wx/lakala_public_key.cer + * @param keepLineBreaks 保留换行符 + * @return + */ + public static String getResourceFile(String fileName, boolean keepLineBreaks, boolean stripPemHeaders) { StringBuilder stringBuilder = new StringBuilder(); try (InputStream inputStream = new ClassPathResource(fileName).getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); @@ -71,6 +83,9 @@ public class LakalaUtil { while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line).append(endSeq); } + if (stripPemHeaders) { + return stripPemHeaders(stringBuilder.toString()); + } return stringBuilder.toString(); } catch (IOException e) { // 记录异常信息 @@ -79,6 +94,76 @@ public class LakalaUtil { } } + /** + * 拉卡拉使用私钥加密数据 + */ + public static String encryptNotifyData(String priKey, String data) { + ByteArrayOutputStream out = null; + try { + log.debug("拉卡拉tk加密私钥:{}", priKey); + log.debug("拉卡拉tk待加密data数据:{}", data); + + // 解码私钥 + byte[] keyBytes = java.util.Base64.getDecoder().decode(priKey); + + // 生成私钥对象 + PrivateKey privateKey = KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); + + // 初始化加密器 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + + // 分段加密 + byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); + out = new ByteArrayOutputStream(); + for (int offset = 0; offset < dataBytes.length; offset += 117) { + int blockSize = Math.min(117, dataBytes.length - offset); + byte[] encryptedBlock = cipher.doFinal(dataBytes, offset, blockSize); + out.write(encryptedBlock); + } + + // 编码为Base64字符串 + String encryptDataStr = java.util.Base64.getEncoder().encodeToString(out.toByteArray()); + log.debug("拉卡拉tk数据加密结果:{}", encryptDataStr); + return encryptDataStr; + } catch (Exception e) { + throw new RuntimeException("私钥加密失败", e); + } finally { + closeQuietly(out); + } + } + + /** + * 安全关闭流 + */ + private static void closeQuietly(ByteArrayOutputStream out) { + if (out != null) { + try { + out.close(); + } catch (Exception e) { + // 忽略异常 + } + } + } + + public static String stripPemHeaders(String key) { + if (key == null || key.isEmpty()) { + return key; + } + + // 定义正则表达式:匹配标签行、任意数量连字符和空白字符 + // 1. 包含BEGIN或END的标签行(无论连字符数量) + // 2. 单独的连字符(不在标签行中的) + // 3. 空白字符(空格、制表符、换行等) + Pattern pattern = Pattern.compile( + "-*BEGIN[^-]*-*|-*END[^-]*-*|-|\\s"); + + // 执行替换 + Matcher matcher = pattern.matcher(key); + return matcher.replaceAll(""); + } + /** * 获取 body 请求数据 * @@ -133,7 +218,6 @@ public class LakalaUtil { } } - /** * 签名验证 * @@ -158,7 +242,6 @@ public class LakalaUtil { } } - /** * 签名校验 * @@ -239,4 +322,85 @@ public class LakalaUtil { return map; } + + /** + * 拼接拉卡拉header中的Authorization字段 + * 参考文档:https://o.lakala.com/#/home/document/detail?id=33 + * + * @param privateKey + * @param appId + * @param serialNo + * @param reqBody + * @return + */ + public static String genAuthorization(String privateKey, String appId, String serialNo, String reqBody) { + if (StrUtil.isBlank(privateKey) || StrUtil.isBlank(appId) || StrUtil.isBlank(serialNo) || StrUtil.isBlank(reqBody)) { + log.error("生产拉卡拉签名时缺少参数"); + return ""; + } + + //待签字符串格式:${appid}\n+${serialNo}\n+${timeStamp}\n+${nonceStr}\n+${body}\n + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = StringUtils.genRandomNumber(12); + String builder = appId + "\n" + + serialNo + "\n" + + timestamp + "\n" + + nonceStr + "\n" + + reqBody + "\n"; + + String signature = RSAUtil.signSHA256withRSA(builder, privateKey); + + return String.format("LKLAPI-SHA256withRSA appid=\"%s\",serial_no=\"%s\",timestamp=\"%s\",nonce_str=\"%s\",signature=\"%s\"", + appId, serialNo, timestamp, nonceStr, signature); + } + + /** + * 拉卡拉异步通知数据公钥解密 + * + * @param pubKey Base64公钥 + * @param data Base64数据 + * @return 解密字符串 + */ + public static String decryptNotifyData(String pubKey, String data) { + ByteArrayOutputStream out = null; + try { + log.debug("拉卡拉tk解密公钥:{}", pubKey); + log.debug("拉卡拉tk待解密data数据:{}", data); + java.util.Base64.Decoder decoder = java.util.Base64.getDecoder(); + byte[] keyBytes = decoder.decode(pubKey.getBytes(StandardCharsets.UTF_8)); + byte[] dataBytes = decoder.decode(data.getBytes(StandardCharsets.UTF_8)); + Cipher cipher = Cipher.getInstance("RSA"); + PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes)); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + out = new ByteArrayOutputStream(); + byte[] cache; + for (int i = 0, offset = 0, length = dataBytes.length; length - offset > 0; i++, offset = i * 128) { + if (length - offset > 128) { + cache = cipher.doFinal(dataBytes, offset, 128); + } else { + cache = cipher.doFinal(dataBytes, offset, length - offset); + } + out.write(cache, 0, cache.length); + } + + String decodedDataStr = out.toString("UTF-8"); + log.debug("拉卡拉tk数据解密结果:{}", decodedDataStr); + + return decodedDataStr; + } catch (IllegalArgumentException e) { + log.error("Base64解码失败: {}", e.getMessage(), e); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + log.error("RSA算法初始化失败: {}", e.getMessage(), e); + } catch (InvalidKeySpecException | InvalidKeyException e) { + log.error("私钥格式或类型错误: {}", e.getMessage(), e); + } catch (BadPaddingException | IllegalBlockSizeException e) { + log.error("解密数据块大小或填充错误: {}", e.getMessage(), e); + } catch (Exception e) { + log.error("解密过程中出现未知异常: {}", e.getMessage(), e); + } finally { + closeQuietly(out); + } + + return null; + } } diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index cb505b4e..becb451a 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -144,7 +144,7 @@ sf-express: #拉卡拉进件配置 lakala: #服务地址 - server_url: https://test.wsmsd.cn/sit + server_url: https://test.wsmsd.cn #应用Id app_id: OP00000003 #商户证书序列号 diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 216eeb06..747e6224 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -144,7 +144,7 @@ sf-express: #拉卡拉进件配置 lakala: #服务地址 - server_url: https://test.wsmsd.cn/sit + server_url: https://test.wsmsd.cn #应用Id app_id: OP00000003 #商户证书序列号 @@ -164,7 +164,7 @@ lakala: # 拉卡拉拓客进件配置 tk: #服务地址 - server_url: https://test.wsmsd.cn + server_url: https://test.wsmsd.cn/sit client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index a12f91c2..dec156a2 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -171,7 +171,7 @@ lakala: # #终端号码,M0780629(B2B收银台) M0780798(专业化扫码) # term_no: M0780798 #服务地址 - server_url: https://test.wsmsd.cn/sit + server_url: https://test.wsmsd.cn #应用Id app_id: OP00000003 #商户证书序列号 diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 55d0859f..2a0b773d 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -148,7 +148,7 @@ sf-express: #拉卡拉进件配置 lakala: #服务地址 - server_url: https://test.wsmsd.cn/sit + server_url: https://test.wsmsd.cn #应用Id app_id: OP00000003 #商户证书序列号 diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 55d0859f..2a0b773d 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -148,7 +148,7 @@ sf-express: #拉卡拉进件配置 lakala: #服务地址 - server_url: https://test.wsmsd.cn/sit + server_url: https://test.wsmsd.cn #应用Id app_id: OP00000003 #商户证书序列号 From 98275e159399fd33df9c06d1aecf8466c2cd2181 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 16 May 2025 07:04:34 +0800 Subject: [PATCH 25/39] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=20=E5=85=A5?= =?UTF-8?q?=E7=BD=91=E7=94=B5=E5=AD=90=E5=90=88=E5=90=8C=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E5=8A=A0=E5=AF=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suisung/mall/common/utils/RSAUtil.java | 2 +- .../impl/EsignContractServiceImpl.java | 2 +- .../controller/mobile/LakalaController.java | 2 +- .../shop/lakala/service/LakalaApiService.java | 9 ++ .../lakala/service/LklLedgerEcService.java | 3 +- .../service/impl/LakalaApiServiceImpl.java | 92 +++++++++++++++++-- .../service/impl/LklLedgerEcServiceImpl.java | 6 +- 7 files changed, 101 insertions(+), 15 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java index ff063c95..01e9a237 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/RSAUtil.java @@ -31,7 +31,7 @@ public class RSAUtil { */ public static String signSHA256withRSA(String data, String privateKey) { try { - // 解码私钥 + // 解码私钥, 并去掉头尾的标识 byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index 03c51055..fa81915a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -198,7 +198,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl innerApplyLedgerMer(String merCupNo); + /** + * 商户入网电子合同申请回调通知 + * 参考:https://o.lakala.com/#/home/document/detail?id=289 + * + * @param request + * @return + */ + JSONObject applyLedgerMerEcNotify(HttpServletRequest request); + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java index 5d8a82b0..f771e4cf 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java @@ -34,9 +34,10 @@ public interface LklLedgerEcService extends IBaseService { * 根据接applyId查询记录 * * @param applyId + * @param status * @return */ - LklLedgerEc getByApplyId(Long applyId); + LklLedgerEc getByApplyId(Long applyId, Integer status); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index a6df3255..7e016fe6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -509,13 +509,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { LocalDate today = LocalDate.now(); // 获取当前日期 String signDate = today.getYear() + "-" + today.getMonthValue() + "-" + today.getDayOfMonth(); + String platformName = "桂平发发网络有限公司"; + String ratioNum = "0.6"; + if (isProd()) { + ratioNum = "0.25"; + } JSONObject ecParams = new JSONObject(); ecParams.put("A1", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); - ecParams.put("A30", "0.6"); // 测试环境微信费率0.6 - ecParams.put("A96", "D1"); - ecParams.put("A97", "开通"); - ecParams.put("A100", "不开通"); + ecParams.put("A30", ratioNum); // 测试环境微信费率0.6 + ecParams.put("A96", "1"); + ecParams.put("A97", "是"); + ecParams.put("A100", "否"); ecParams.put("A101", "中国境内"); + ecParams.put("A102", platformName); + ecParams.put("A103", "小发同城"); ecParams.put("A104", today.getYear()); ecParams.put("A105", today.getMonthValue()); ecParams.put("A106", today.getDayOfMonth()); @@ -523,11 +530,13 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("A108", today.getMonthValue()); ecParams.put("A109", today.getDayOfMonth()); ecParams.put("B1", today.getYear()); + ecParams.put("B3", "是"); ecParams.put("B2", today.getMonthValue()); ecParams.put("B8", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); - ecParams.put("B9", shopMchEntry.getSales_info()); + ecParams.put("B9", StrUtil.subSufByLength(shopMchEntry.getSales_info(), 22)); ecParams.put("B10", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); ecParams.put("B14", isQy ? shopMchEntry.getBiz_license_number() : ""); + ecParams.put("B16", isQy ? "是" : "否"); ecParams.put("B19", shopMchEntry.getOpenning_bank_code()); ecParams.put("B20", shopMchEntry.getAccount_number()); ecParams.put("B31", shopMchEntry.getStore_name()); @@ -536,16 +545,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("B34", shopMchEntry.getLogin_mobile()); ecParams.put("D1", shopMchEntry.getBank_name()); ecParams.put("D2", signDate); - ecParams.put("D4", "桂平发发网络有限公司"); + ecParams.put("D4", platformName); ecParams.put("D7", signDate); ecParams.put("D9", signDate); ecParams.put("D11", signDate); ecParams.put("D12", signDate); - ecParams.put("E1", "桂平发发网络有限公司"); - ecParams.put("E2", "商户入驻小发同城平台合同协议"); - ecParams.put("E3", "0"); + ecParams.put("E1", platformName); + ecParams.put("E2", "小发同城平台商户合作协议"); + ecParams.put("E3", "2"); ecParams.put("E4", "70"); - ecParams.put("E5", "桂平发发网络有限公司"); + ecParams.put("E5", platformName); ecParams.put("E7", signDate); ecParams.put("E8", shopMchEntry.getAccount_holder_name()); @@ -792,6 +801,69 @@ public class LakalaApiServiceImpl implements LakalaApiService { } } + /** + * 商户入网电子合同申请回调通知 + * 参考:https://o.lakala.com/#/home/document/detail?id=289 + * + * @param request + * @return + */ + @Override + public JSONObject applyLedgerMerEcNotify(HttpServletRequest request) { + log.info("商户入网电子合同申请回调通知开始"); + + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + log.info("商户入网电子合同申请回调返回参数:{}", requestBody); + + boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); + if (!checkSuccess) { + log.info("商户入网电子合同申请回调:验签失败"); + return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + } + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); + + JSONObject respData = new JSONObject(); + respData.put("retCode", "OP90003"); + respData.put("retMsg", "系统处理失败!"); + + if (paramsJSON != null) { + Long ecApplyId = paramsJSON.getLong("ecApplyId"); + String ecNo = paramsJSON.getStr("ecNo"); + if (ecApplyId == null || StrUtil.isBlank(ecNo)) { + log.info("商户入网电子合同申请回调:ecApplyId 为空"); + respData.put("retMsg", "ecApplyId 返回空值!"); + return respData; + } + + if (lklLedgerEcService.getByApplyId(ecApplyId, CommonConstant.Enable) != null) { + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.info("商户入网电子合同申请回调:已处理成功,不需再重新处理"); + } + + // 更改本地分账记录状态数据 + LklLedgerEc updRecord = new LklLedgerEc(); + updRecord.setEc_apply_id(ecApplyId); + updRecord.setEc_no(ecNo); + updRecord.setEc_name(paramsJSON.getStr("ecName")); + updRecord.setEc_status(paramsJSON.getStr("ecStatus")); + // 更新本地数据状态和合同编号、合同名字 + Boolean success = lklLedgerEcService.updateByApplyId(updRecord); + if (success) { + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.info("商户入网电子合同申请回调:处理成功"); + + // 更新商家入驻表的合同编号,合同名称 + } + } + + return respData; + } + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java index 3572c05a..c2dc8acc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java @@ -107,13 +107,17 @@ public class LklLedgerEcServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); queryWrapper.eq("ec_apply_id", applyId); + if (ObjectUtil.isNotEmpty(status)) { + queryWrapper.eq("status", status); + } + return getOne(queryWrapper); } From 3f35de950752e8a0d6f9029b00865ec0e21c5d54 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 16 May 2025 10:24:12 +0800 Subject: [PATCH 26/39] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=E9=93=B6?= =?UTF-8?q?=E8=A1=8C=E6=90=9C=E7=B4=A2=EF=BC=8C=E5=B8=A6=E5=87=BA=E5=8C=BA?= =?UTF-8?q?=E5=9F=9Fcode=20=E5=92=8C=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/mobile/LklTkController.java | 7 ++-- .../shop/lakala/mapper/LklBanksMapper.java | 8 ++++ .../shop/lakala/service/LklBanksService.java | 6 +++ .../service/impl/LklBanksServiceImpl.java | 20 +++++++++ .../mapper/lakala/LklBanksMapper.xml | 41 +++++++++++++++++++ 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index a309497a..735007d6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -9,9 +9,8 @@ package com.suisung.mall.shop.lakala.controller.mobile; import cn.hutool.json.JSONObject; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.suisung.mall.common.api.CommonResult; -import com.suisung.mall.common.modules.lakala.LklBanks; import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.lakala.service.LklBanksService; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; @@ -26,6 +25,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import java.util.Map; @Api(tags = "拉卡拉商户进件控制器") @RestController @@ -50,7 +50,8 @@ public class LklTkController extends BaseControllerImpl { @ApiOperation(value = "搜索国内银行(支行)分页列表", notes = "搜索国内银行(支行)分页列表,数据包含有效的收款结清行号") @RequestMapping(value = "/bank/search", method = RequestMethod.POST) public CommonResult searchLklBanksPageList(@RequestBody JSONObject paramsJSON) { - Page list = lklBanksService.searchBranchBanksPageList(paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); +// Page list = lklBanksService.searchBranchBanksPageList(paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); + IPage list = lklBanksService.pageBranchBanksList("", "", 2, paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize")); return CommonResult.success(list); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java index fcf12d4e..c017aa46 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklBanksMapper.java @@ -9,10 +9,18 @@ package com.suisung.mall.shop.lakala.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.modules.lakala.LklBanks; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Map; + @Repository public interface LklBanksMapper extends BaseMapper { + + IPage pageBranchBanksList(Page page, @Param("bankNo") String bankNo, @Param("branchBankNo") String branchBankNo, @Param("type") Integer type, @Param("keywords") List keywords); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java index 347ac4cd..7edeeb9e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java @@ -8,9 +8,12 @@ package com.suisung.mall.shop.lakala.service; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.modules.lakala.LklBanks; +import java.util.Map; + public interface LklBanksService { /** @@ -22,4 +25,7 @@ public interface LklBanksService { * @return */ Page searchBranchBanksPageList(String keyword, Integer pageNum, Integer pageSize); + + + IPage pageBranchBanksList(String bankNo, String branchBankNo, Integer type, String keyword, Integer pageNum, Integer pageSize); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java index 1a7795da..4d9a15c9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java @@ -10,6 +10,7 @@ package com.suisung.mall.shop.lakala.service.impl; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.lakala.LklBanks; @@ -22,6 +23,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; +import java.util.Map; @Slf4j @Service @@ -30,6 +32,9 @@ public class LklBanksServiceImpl extends BaseServiceImpl pageBranchBanksList(String bankNo, String branchBankNo, Integer type, String keyword, Integer pageNum, Integer pageSize) { + Page page = new Page<>(pageNum, pageSize); + return lklBanksMapper.pageBranchBanksList(page, bankNo, branchBankNo, type, jiebaUtils.segmentForSearch(keyword)); + } } diff --git a/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml b/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml index 8e026578..8d914dae 100644 --- a/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml +++ b/mall-shop/src/main/resources/mapper/lakala/LklBanksMapper.xml @@ -5,4 +5,45 @@ * + + From 2feebfafd4f8888f3f280e68338ae58d343b3b98 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sat, 17 May 2025 11:10:45 +0800 Subject: [PATCH 27/39] =?UTF-8?q?=E5=88=86=E8=B4=A6=E6=AF=94=E4=BE=8B=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=85=8D=E7=BD=AE=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modules/lakala/LklLedgerEc.java | 1 + .../common/modules/store/ShopMchEntry.java | 9 + .../suisung/mall/common/utils/UploadUtil.java | 52 ++++++ .../controller/mobile/LakalaController.java | 3 +- .../controller/mobile/LklTkController.java | 2 +- .../shop/lakala/service/LakalaApiService.java | 9 + .../shop/lakala/service/LklBanksService.java | 21 ++- .../lakala/service/LklLedgerEcService.java | 12 +- .../service/impl/LakalaApiServiceImpl.java | 162 ++++++++++++++++-- .../service/impl/LklBanksServiceImpl.java | 21 +++ .../service/impl/LklLedgerEcServiceImpl.java | 49 +++--- .../lakala/service/impl/LklTkServiceImpl.java | 44 ++++- .../store/service/ShopMchEntryService.java | 12 ++ .../service/impl/ShopMchEntryServiceImpl.java | 52 +++++- .../src/main/resources/bootstrap-dev.yml | 1 + .../src/main/resources/bootstrap-local.yml | 1 + .../src/main/resources/bootstrap-prod.yml | 1 + .../src/main/resources/bootstrap-test.yml | 1 + .../src/main/resources/bootstrap-uat.yml | 1 + 19 files changed, 399 insertions(+), 55 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java index 3aa80583..d87557ea 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java @@ -38,6 +38,7 @@ public class LklLedgerEc implements Serializable { private String resp_notify_body; private String ec_no; private String ec_name; + private String ec_file; private String ec_status; private Long ec_apply_id; private String result_url; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index d792a763..831bcedc 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -223,6 +223,15 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉进件成功返回的JSON数据") private String lkl_tk_reg_resp; + @ApiModelProperty(value = "拉卡拉入网电子合同编号(进件必须使用)") + private String lkl_ec_no; + + @ApiModelProperty(value = "拉卡拉入网电子合同名称") + private String lkl_ec_name; + + @ApiModelProperty(value = "拉卡拉入网电子合同签署H5地址(进件必须使用)") + private String lkl_ec_result_url; + @ApiModelProperty(value = "合同签署状态:0-无任何签署;1-一方签署;2-双方已签署;") private Integer signed_status; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java index cf21cbbf..1d44950a 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java @@ -369,5 +369,57 @@ public class UploadUtil { return path.substring(lastIndex + 1); } + /** + * 将 base64UrlSafeString Base64字符串转换为文件 + * + * @param base64UrlSafeString + * @return + */ + public static File convertBase64ToFile(String base64UrlSafeString) { + // 输入校验 + if (base64UrlSafeString == null || base64UrlSafeString.isEmpty()) { + log.error("Base64字符串不能为空"); + return null; + // throw new IllegalArgumentException("Base64字符串不能为空"); + } + + try { + // 1. 替换URL安全字符为标准Base64字符 + String standardBase64 = base64UrlSafeString.replace('-', '+').replace('_', '/'); + + // 2. 补齐缺失的填充字符 '=' + while (standardBase64.length() % 4 != 0) { + standardBase64 += '='; + } + + // 3. 解码为字节数组 + byte[] decodedBytes = Base64Utils.decodeFromString(standardBase64); + + // 4. 创建临时文件(自动生成唯一文件名) + File tempFile = File.createTempFile("base64-", ".tmp"); + + // 5. 设置JVM退出时自动删除(可选) + tempFile.deleteOnExit(); + + // 6. 写入文件内容 + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + fos.write(decodedBytes); + } + + return tempFile; + + } catch (IllegalArgumentException e) { + // 处理Base64解码失败 +// throw new IllegalArgumentException("无效的Base64字符串: " + e.getMessage(), e); + log.error("无效的Base64字符串: " + e.getMessage()); + return null; + } catch (IOException e) { + // 处理文件操作异常 +// throw new RuntimeException("临时文件创建失败: " + e.getMessage(), e); + log.error("临时文件创建失败: " + e.getMessage()); + return null; + } + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 0f00d39f..39b82604 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -33,7 +33,8 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "测试案例", notes = "测试案例") @RequestMapping(value = "/testcase", method = RequestMethod.POST) public Object testcase(@RequestBody JSONObject paramsJSON) { - return lakalaPayService.applyLedgerMerEc(paramsJSON.getStr("mchMobile")); +// return lakalaPayService.applyLedgerMerEc(paramsJSON.getStr("mchMobile")); + return lakalaPayService.LedgerMerEcDownload(975790666910121984L); } @ApiOperation(value = "本地文件转base64", notes = "本地文件转base64") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java index 735007d6..27341391 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LklTkController.java @@ -68,7 +68,7 @@ public class LklTkController extends BaseControllerImpl { // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify @ApiOperation(value = "拉卡拉进件申请异步回调通知", notes = "拉卡拉进件申请异步回调通知") - @RequestMapping(value = "/registrationMerchantNotify", method = {RequestMethod.POST, RequestMethod.GET}) + @RequestMapping(value = "/registrationMerchantNotify", method = {RequestMethod.POST}) public ResponseEntity registrationMerchantNotify(HttpServletRequest request) { JSONObject resp = lklTkService.registrationMerchantNotify(request); if (resp != null && resp.get("code").equals("200")) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 0f354a8a..0e1fea84 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -125,6 +125,15 @@ public interface LakalaApiService { */ JSONObject applyLedgerMerEcNotify(HttpServletRequest request); + /** + * 商户入网电子合同下载 + * 参考:https://o.lakala.com/#/home/document/detail?id=294 + * + * @param ecApplyId + * @return + */ + String LedgerMerEcDownload(Long ecApplyId); + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java index 7edeeb9e..49adae14 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklBanksService.java @@ -17,7 +17,7 @@ import java.util.Map; public interface LklBanksService { /** - * 根据关键字查询有效记录分页列表 + * 根据关键字查询有效记录分页列表(不带地区) * * @param keyword * @param pageNum @@ -27,5 +27,24 @@ public interface LklBanksService { Page searchBranchBanksPageList(String keyword, Integer pageNum, Integer pageSize); + /** + * 根据关键字分词进行分页查询支行列表(带省市地区) + * + * @param bankNo 总行号 + * @param branchBankNo 支行号 + * @param type 1-店铺地区;2-银行地区 + * @param keyword 查询关键字,做分词 + * @param pageNum + * @param pageSize + * @return + */ IPage pageBranchBanksList(String bankNo, String branchBankNo, Integer type, String keyword, Integer pageNum, Integer pageSize); + + /** + * 根据支行号查询支行信息(带省市地区) + * + * @param branchBankNo 支行号 + * @return + */ + Map GetLklBankByBranchBankNo(String branchBankNo); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java index f771e4cf..63afe7aa 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerEcService.java @@ -8,7 +8,6 @@ package com.suisung.mall.shop.lakala.service; -import cn.hutool.json.JSONObject; import com.suisung.mall.common.modules.lakala.LklLedgerEc; import com.suisung.mall.core.web.service.IBaseService; @@ -34,18 +33,21 @@ public interface LklLedgerEcService extends IBaseService { * 根据接applyId查询记录 * * @param applyId + * @param ecStatus * @param status * @return */ - LklLedgerEc getByApplyId(Long applyId, Integer status); - + LklLedgerEc getByApplyId(Long applyId, String ecStatus, Integer status); /** - * 通过mchId商家Id记录信息构建申请入网电子合同的请求参数 + * 根据商户手机号查询记录 * * @param mchMobile + * @param ecStatus + * @param status * @return */ - JSONObject buildApplyLedgerEcReqParams(String mchMobile); + LklLedgerEc getByMchMobile(String mchMobile, String ecStatus, Integer status); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 7e016fe6..0eb47c58 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -34,6 +34,7 @@ import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.lakala.service.*; import com.suisung.mall.shop.lakala.utils.LakalaUtil; +import com.suisung.mall.shop.page.service.OssService; import com.suisung.mall.shop.store.service.ShopMchEntryService; import com.suisung.mall.shop.store.service.ShopStoreBaseService; import lombok.extern.slf4j.Slf4j; @@ -49,6 +50,7 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.File; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -83,10 +85,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签) @Value("${lakala.org_code}") private String orgCode; + @Value("${lakala.tk.ratio}") + private String ratio; @Value("${project.domain}") private String projectDomain; @Value("${spring.profiles.active}") private String profile; + + @Value("#{accountBaseConfigService.getConfig('tengxun_default_dir')}") + private String TENGXUN_DEFAULT_DIR; + @Lazy @Autowired private ShopService shopService; @@ -122,6 +130,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Autowired private LklLedgerEcService lklLedgerEcService; + @Lazy + @Resource + private LklTkServiceImpl lklTkService; + + @Resource + private OssService ossService; + + /** * 初始化 拉卡拉SDK * @@ -136,7 +152,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { } protected boolean isProd() { - return "prod".equalsIgnoreCase(profile); + return false; + // 正式发布时再启用 + //return "prod".equalsIgnoreCase(profile); } @Override @@ -454,7 +472,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { } /** - * 商家申请入网电子合同 + * 商家申请入网电子合同(给到商家签署合同) * * @param mchMobile * @return @@ -472,6 +490,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, I18nUtil._("无法查找商家相关信息!")); } + LklLedgerEc lklLedgerEc = lklLedgerEcService.getByMchMobile(mchMobile, "", CommonConstant.Enable); + if (lklLedgerEc != null && "COMPLETED".equals(lklLedgerEc.getEc_status())) { + return Pair.of(true, I18nUtil._("商家已经申请过入网电子合同!")); + } + // 是企业类型商家 Boolean isQy = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()); @@ -502,8 +525,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (isProd()) { domain += "/api"; } - // 给拉卡拉通知的回调地址 - String retUrl = domain + "/mobile/shop/lakala/ec/applyNotify"; + // 给拉卡拉通知的回调地址 TODO 生产环境一定去掉 api + String retUrl = domain + "/api/mobile/shop/lakala/ec/applyNotify"; reqData.put("ret_url", retUrl); LocalDate today = LocalDate.now(); // 获取当前日期 @@ -546,6 +569,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("D1", shopMchEntry.getBank_name()); ecParams.put("D2", signDate); ecParams.put("D4", platformName); + ecParams.put("D5", shopMchEntry.getLogin_mobile()); ecParams.put("D7", signDate); ecParams.put("D9", signDate); ecParams.put("D11", signDate); @@ -553,12 +577,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("E1", platformName); ecParams.put("E2", "小发同城平台商户合作协议"); ecParams.put("E3", "2"); - ecParams.put("E4", "70"); ecParams.put("E5", platformName); + ecParams.put("E6", ratio); ecParams.put("E7", signDate); ecParams.put("E8", shopMchEntry.getAccount_holder_name()); - // 注:该字段是字符串,不是json + // 注:该字段是json字符串,不是json对象 reqData.put("ec_content_parameters", ecParams.toString()); JSONObject reqBody = new JSONObject(); @@ -609,7 +633,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, "商家入网申请电子合同失败:本地数据保存失败"); } - return Pair.of(true, "商家入网申请电子合同成功"); } @@ -638,7 +661,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) - req.setSplitLowestRatio(BigDecimal.valueOf(70)); + req.setSplitLowestRatio(new BigDecimal(ratio)); String fileName = paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); @@ -699,7 +722,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Override public Pair innerApplyLedgerMer(String merCupNo) { - log.info("商户分账业务开通申请开始"); + log.debug("商户分账业务开通申请开始"); if (StringUtils.isBlank(merCupNo)) { return Pair.of(false, I18nUtil._("商户号不能为空!")); @@ -730,7 +753,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) - req.setSplitLowestRatio(BigDecimal.valueOf(70)); + req.setSplitLowestRatio(new BigDecimal(ratio)); + req.setEleContractNo(shopMchEntry.getLkl_ec_no()); String fileName = "小发同城分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); @@ -832,23 +856,42 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (paramsJSON != null) { Long ecApplyId = paramsJSON.getLong("ecApplyId"); String ecNo = paramsJSON.getStr("ecNo"); + String ecStatus = paramsJSON.getStr("ecStatus"); // COMPLETED + if (ecStatus == null || !ecStatus.equals("COMPLETED")) { + log.info("商户入网电子合同申请状态尚未签署完成!"); + respData.put("retMsg", "入网电子合同尚未签署完成!"); + return respData; + } + if (ecApplyId == null || StrUtil.isBlank(ecNo)) { log.info("商户入网电子合同申请回调:ecApplyId 为空"); respData.put("retMsg", "ecApplyId 返回空值!"); return respData; } - if (lklLedgerEcService.getByApplyId(ecApplyId, CommonConstant.Enable) != null) { + LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); + if (lklLedgerEc == null) { + log.info("商户入网电子合同申请回调:未找到对应的入网电子合同记录"); + respData.put("retMsg", "未找到对应的入网电子合同记录!"); + return respData; + } + + if ("COMPLETED".equals(lklLedgerEc.getEc_status())) { respData.put("retCode", lklSuccessCode); respData.put("retMsg", "操作成功!"); log.info("商户入网电子合同申请回调:已处理成功,不需再重新处理"); + return respData; } - // 更改本地分账记录状态数据 + // 把 base64 合同文件,上传到 cos 服务器,返回 url 地址 + String ecFileUrl = LedgerMerEcDownload(ecApplyId); + + // 更改本地记录状态数据 LklLedgerEc updRecord = new LklLedgerEc(); updRecord.setEc_apply_id(ecApplyId); updRecord.setEc_no(ecNo); updRecord.setEc_name(paramsJSON.getStr("ecName")); + updRecord.setEc_file(ecFileUrl); // 合同本地文件COS URL链接 updRecord.setEc_status(paramsJSON.getStr("ecStatus")); // 更新本地数据状态和合同编号、合同名字 Boolean success = lklLedgerEcService.updateByApplyId(updRecord); @@ -857,13 +900,106 @@ public class LakalaApiServiceImpl implements LakalaApiService { respData.put("retMsg", "操作成功!"); log.info("商户入网电子合同申请回调:处理成功"); - // 更新商家入驻表的合同编号,合同名称 + // 更新商家入驻表的合同编号,和签署地址 + shopMchEntryService.updateMerchEntryLklEcNo(lklLedgerEc.getMch_id(), ecNo, paramsJSON.getStr("ecName"), lklLedgerEc.getResult_url(), ecFileUrl); + + // TODO 商家电子合同签署完毕后,收到异步通知,触发拉卡拉商家进件(重要环节) + // 下一步,等待拉卡拉系统审核,和人工审核,收到异步通知之后,触发1、e签宝的电子合同签署,2、新增分账接收方 + Pair resultPair = lklTkService.registrationMerchant(lklLedgerEc.getMch_mobile(), ""); + if (!resultPair.getFirst()) { + log.error("###商户入网电子合同签署通知回调:拉卡拉商家进件失败:", resultPair.getSecond()); + // return CommonResult.failed(resultPair.getSecond()); + } } } return respData; } + /** + * 商户入网盖章电子合同下载 + * + * @param ecApplyId + * @return + */ + @Override + public String LedgerMerEcDownload(Long ecApplyId) { + log.debug("商家开始申请入网电子合同"); + if (ObjectUtil.isEmpty(ecApplyId)) { + return ""; + } + + JSONObject reqData = new JSONObject(); + reqData.put("order_no", StringUtils.genLklOrderNo(8)); + reqData.put("org_code", orgCode); + reqData.put("ec_apply_id", ecApplyId); + + JSONObject reqBody = new JSONObject(); + reqBody.put("req_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss")); + reqBody.put("version", "1.0"); + reqBody.put("req_data", reqData); + + String reqUrl = serverUrl + "/sit/api/v3/mms/open_api/ec/download"; + if (isProd()) { + reqUrl = serverUrl + "/api/v3/mms/open_api/ec/download"; + } + + String privateKey = LakalaUtil.getResourceFile(priKeyPath, false, true); + String authorization = LakalaUtil.genAuthorization(privateKey, appId, serialNo, reqBody.toString()); + + JSONObject header = new JSONObject(); + header.put("Authorization", authorization); + + ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class); + if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { + log.error("下载电子合同失败:返回状态有误!"); + return ""; + } + + JSONObject respBody = response.getBody(); + if (ObjectUtil.isNotEmpty(respBody) && !lklSuccessCode.equals(respBody.getStr("code"))) { + String errMsg = StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg"); + log.error("下载电子合同失败:{}!", errMsg); + return ""; + } + + JSONObject respData = respBody.getJSONObject("resp_data"); + if (respBody.getJSONObject("resp_data") == null) { + log.error("下载电子合同失败:返回数据有误!"); + return ""; + } + + String ecFile = respData.getStr("ec_file"); + if (StrUtil.isBlank(ecFile)) { + log.error("下载电子合同失败:返回数据有误!"); + return ""; + } + + LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); + if (lklLedgerEc == null) { + log.error("下载电子合同失败:未找到对应的入网电子合同记录"); + return ""; + } + + String fileBase64 = respData.getStr("ec_file"); + File file = UploadUtil.convertBase64ToFile(fileBase64); + + // REMARK 把合同文件 url 上传到cos服务器 + String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract") + .concat("/") + .concat(lklLedgerEc.getMch_mobile()).concat("/") + .concat("signed").concat("/") + .concat(ecApplyId.toString()).concat(".pdf"); + + // 上传到cos服务器 + String cosFileUrl = ossService.uploadObject4OSS(file, cosFileName); + + // 删除临时文件 + file.delete(); + + return cosFileUrl; + } + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java index 4d9a15c9..ff3b762a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklBanksServiceImpl.java @@ -8,6 +8,7 @@ package com.suisung.mall.shop.lakala.service.impl; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -93,4 +94,24 @@ public class LklBanksServiceImpl extends BaseServiceImpl page = new Page<>(pageNum, pageSize); return lklBanksMapper.pageBranchBanksList(page, bankNo, branchBankNo, type, jiebaUtils.segmentForSearch(keyword)); } + + /** + * 根据支行号查询支行信息(带省市地区) + * + * @param branchBankNo 支行号 + * @return + */ + @Override + public Map GetLklBankByBranchBankNo(String branchBankNo) { + if (StrUtil.isBlank(branchBankNo)) { + return null; + } + + IPage list = lklBanksMapper.pageBranchBanksList(new Page<>(1, 1), null, branchBankNo, 2, null); + if (list == null || CollectionUtil.isEmpty(list.getRecords())) { + return null; + } + + return list.getRecords().get(0); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java index c2dc8acc..2cf0f6ca 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerEcServiceImpl.java @@ -11,10 +11,8 @@ package com.suisung.mall.shop.lakala.service.impl; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.lakala.LklLedgerEc; -import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; import com.suisung.mall.shop.lakala.mapper.LklLedgerEcMapper; @@ -104,10 +102,12 @@ public class LklLedgerEcServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("mch_mobile", mchMobile).orderByDesc("id"); + if (ObjectUtil.isNotEmpty(status)) { + queryWrapper.eq("status", status); + } + + if (StrUtil.isNotEmpty(ecStatus)) { + queryWrapper.eq("ec_status", ecStatus); + } + + List lklLedgerEcList = list(queryWrapper); + if (CollectionUtil.isEmpty(lklLedgerEcList)) { return null; } - JSONObject jsonObject = new JSONObject(); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - jsonObject.put("mch_id", shopMchEntry.getId()); - - - return jsonObject; + return lklLedgerEcList.get(0); } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 19abcc55..6754aba2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -25,6 +25,7 @@ import com.suisung.mall.common.utils.UploadUtil; import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; +import com.suisung.mall.shop.lakala.service.LklBanksService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; import com.suisung.mall.shop.lakala.utils.LakalaUtil; import com.suisung.mall.shop.page.service.impl.OssServiceImpl; @@ -86,6 +87,10 @@ public class LklTkServiceImpl { @Resource private EsignContractFillingFileService esignContractFillingFileService; + @Lazy + @Resource + private LklBanksService lklBanksService; + @Lazy @Resource private OssServiceImpl ossService; @@ -340,7 +345,8 @@ public class LklTkServiceImpl { } formData.put("contactMobile", mchMobile); - formData.put("contactName", shopMchEntry.getContact_name()); + formData.put("contactName", shopMchEntry.getContact_name());// 联系人姓名 + formData.put("contractNo", shopMchEntry.getLkl_ec_no()); // 拉卡拉入网合同编号 // 银行账号关键字段 formData.put("openningBankCode", shopMchEntry.getOpenning_bank_code());//结算账户开户⾏号 @@ -364,14 +370,34 @@ public class LklTkServiceImpl { } //结算信息省市信息 - Map bankAreaCode = getAreaCode(shopMchEntry.getBank_area(), true); - if (ObjectUtil.isNotEmpty(bankAreaCode)) { - formData.put("settleProvinceCode", bankAreaCode.get("provinceCode")); - formData.put("settleCityCode", bankAreaCode.get("cityCode")); - String[] bankAreaName = shopMchEntry.getBank_area().split(","); - if (bankAreaName.length >= 2) { - formData.put("settleProvinceName", bankAreaName[0]); - formData.put("settleCityName", bankAreaName[1]); + if (StrUtil.isBlank(shopMchEntry.getBank_district()) || StrUtil.isBlank(shopMchEntry.getBank_area())) { + Map bankInfo = lklBanksService.GetLklBankByBranchBankNo(shopMchEntry.getOpenning_bank_code()); + if (ObjectUtil.isNotEmpty(bankInfo)) { + shopMchEntry.setBank_district(bankInfo.get("district").toString()); + shopMchEntry.setBank_area(bankInfo.get("area").toString()); + } + } + + if (StrUtil.isNotBlank(shopMchEntry.getBank_district()) && StrUtil.isNotBlank(shopMchEntry.getBank_area())) { + // 直接分解取值 + String[] bankAreaCodes = shopMchEntry.getBank_district().split("/"); + String[] bankAreaNames = shopMchEntry.getBank_area().split("/"); + if (bankAreaCodes.length >= 2 && bankAreaNames.length >= 2) { + formData.put("settleProvinceCode", bankAreaCodes[0]); + formData.put("settleProvinceName", bankAreaCodes[1]); + formData.put("settleCityCode", bankAreaNames[0]); + formData.put("settleCityName", bankAreaNames[1]); + } + } else { + Map bankAreaCode = getAreaCode(shopMchEntry.getBank_area(), true); + if (ObjectUtil.isNotEmpty(bankAreaCode)) { + formData.put("settleProvinceCode", bankAreaCode.get("provinceCode")); + formData.put("settleCityCode", bankAreaCode.get("cityCode")); + String[] bankAreaName = shopMchEntry.getBank_area().split("/"); + if (bankAreaName.length >= 2) { + formData.put("settleProvinceName", bankAreaName[0]); + formData.put("settleCityName", bankAreaName[1]); + } } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 12e48493..6a46aa13 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -178,5 +178,17 @@ public interface ShopMchEntryService { */ Boolean updateMerchEntryStoreId(Long id, Integer storeId); + /** + * 更新拉卡拉入网电子合同、合同名称、签署地址 + * + * @param id + * @param lklEcNo + * @param lklEcName + * @param lklEcResultUrl + * @param ecDownloadUrl + * @return + */ + Boolean updateMerchEntryLklEcNo(Long id, String lklEcNo, String lklEcName, String lklEcResultUrl, String ecDownloadUrl); + } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 7389ddd3..0def9e67 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -30,6 +30,7 @@ import com.suisung.mall.shop.components.TaskService; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; +import com.suisung.mall.shop.lakala.service.impl.LakalaApiServiceImpl; import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl; import com.suisung.mall.shop.message.service.ShopMessageTemplateService; import com.suisung.mall.shop.store.mapper.ShopMchEntryMapper; @@ -81,6 +82,10 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl resultPair = lklTkService.registrationMerchant(record.getLogin_mobile(), record.getBiz_license_number()); + if (approvalStatus.equals(CommonConstant.MCH_APPR_STA_NOPASS)) { + return CommonResult.success(null, "驳回成功!"); + } + + // 审批通过的时候,进行下一步工作:触发去拉卡拉商家入网电子合同签署 + + // 平台人工审核通过后,触发去拉卡拉商家入网电子合同签署 + // 下一步:商家入网电子合同签署完毕后,收到异步通知,触发拉卡拉商家进件(重要环节) + Pair resultPair = lakalaApiService.applyLedgerMerEc(record.getLogin_mobile()); if (!resultPair.getFirst()) { return CommonResult.failed(resultPair.getSecond()); } @@ -836,4 +848,40 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", id); + updateWrapper.set("lkl_ec_no", lklEcNo); + + if (StrUtil.isNotBlank(lklEcName)) { + updateWrapper.set("lkl_ec_name", lklEcName); + } + + + if (StrUtil.isNotBlank(lklEcResultUrl)) { + updateWrapper.set("lkl_ec_result_url", lklEcResultUrl); + } + + if (StrUtil.isNotBlank(ecDownloadUrl)) { + updateWrapper.set("contract_download_url", ecDownloadUrl); + } + + + return update(updateWrapper); + } } diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index becb451a..1358c1bf 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -168,6 +168,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 + ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 747e6224..98d11408 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -168,6 +168,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 + ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index dec156a2..55c877c7 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -195,6 +195,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 + ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 2a0b773d..96dbafd4 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -172,6 +172,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 + ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 2a0b773d..96dbafd4 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -172,6 +172,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 + ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt From b865aafadf3fefad5a0d57efc4dd083085a81954 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 18 May 2025 03:51:21 +0800 Subject: [PATCH 28/39] =?UTF-8?q?=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=8Cbug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/LakalaPayServiceImpl.java | 4 +- .../controller/mobile/LakalaController.java | 4 +- .../service/impl/LakalaApiServiceImpl.java | 389 ++++++++++-------- .../impl/LklLedgerMemberServiceImpl.java | 2 +- .../impl/LklLedgerReceiverServiceImpl.java | 4 +- .../lakala/service/impl/LklTkServiceImpl.java | 139 +++++-- .../store/service/ShopMchEntryService.java | 10 + .../service/impl/ShopMchEntryServiceImpl.java | 36 ++ .../impl/ShopStoreBaseServiceImpl.java | 2 +- .../src/main/resources/bootstrap-local.yml | 5 +- .../src/main/resources/bootstrap-prod.yml | 3 +- 11 files changed, 386 insertions(+), 212 deletions(-) diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index a7e1c528..b553420a 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -103,7 +103,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { return true; } - protected boolean isProd() { + protected boolean isProdProject() { return "prod".equalsIgnoreCase(profile); } @@ -432,7 +432,7 @@ public class LakalaPayServiceImpl implements LakalaPayService { String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; - if (isProd()) { + if (isProdProject()) { projectDomain = projectDomain + "/api"; } // 给拉卡拉通知的回调地址 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 39b82604..71e68954 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -33,8 +33,8 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "测试案例", notes = "测试案例") @RequestMapping(value = "/testcase", method = RequestMethod.POST) public Object testcase(@RequestBody JSONObject paramsJSON) { -// return lakalaPayService.applyLedgerMerEc(paramsJSON.getStr("mchMobile")); - return lakalaPayService.LedgerMerEcDownload(975790666910121984L); + return lakalaPayService.applyLedgerMerEc(paramsJSON.getStr("mchMobile")); +// return lakalaPayService.LedgerMerEcDownload(975790666910121984L); } @ApiOperation(value = "本地文件转base64", notes = "本地文件转base64") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 0eb47c58..49a2da64 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -30,8 +30,6 @@ import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.modules.store.ShopStoreBase; import com.suisung.mall.common.utils.*; -import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; -import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.lakala.service.*; import com.suisung.mall.shop.lakala.utils.LakalaUtil; import com.suisung.mall.shop.page.service.OssService; @@ -91,6 +89,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { private String projectDomain; @Value("${spring.profiles.active}") private String profile; + @Value("${lakala.is_prod}") + private Boolean isLklProd; @Value("#{accountBaseConfigService.getConfig('tengxun_default_dir')}") private String TENGXUN_DEFAULT_DIR; @@ -112,14 +112,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { @Resource private ShopMchEntryService shopMchEntryService; - @Lazy - @Resource - private - EsignContractService esignContractService; - - @Lazy - @Resource - private EsignContractFillingFileService esignContractFillingFileService; +// @Lazy +// @Resource +// private +// EsignContractService esignContractService; +// +// @Lazy +// @Resource +// private EsignContractFillingFileService esignContractFillingFileService; @Lazy @@ -151,10 +151,10 @@ public class LakalaApiServiceImpl implements LakalaApiService { return true; } - protected boolean isProd() { - return false; + protected boolean isProdProject() { +// return false; // 正式发布时再启用 - //return "prod".equalsIgnoreCase(profile); + return "prod".equalsIgnoreCase(profile); } @Override @@ -487,7 +487,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 获取商家信息 ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, ""); if (shopMchEntry == null) { - return Pair.of(false, I18nUtil._("无法查找商家相关信息!")); + return Pair.of(false, I18nUtil._("缺少商家相关信息!")); } LklLedgerEc lklLedgerEc = lklLedgerEcService.getByMchMobile(mchMobile, "", CommonConstant.Enable); @@ -521,12 +521,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { reqData.put("acct_name", shopMchEntry.getAccount_holder_name()); reqData.put("remark", "申请入网电子合同"); + // 正式上线的时候,调整 api 地址 String domain = projectDomain; - if (isProd()) { + if (isProdProject()) { domain += "/api"; } + // 给拉卡拉通知的回调地址 TODO 生产环境一定去掉 api - String retUrl = domain + "/api/mobile/shop/lakala/ec/applyNotify"; + String retUrl = domain + "/mobile/shop/lakala/ec/applyNotify"; reqData.put("ret_url", retUrl); LocalDate today = LocalDate.now(); // 获取当前日期 @@ -534,7 +536,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String platformName = "桂平发发网络有限公司"; String ratioNum = "0.6"; - if (isProd()) { + if (isLklProd) { ratioNum = "0.25"; } JSONObject ecParams = new JSONObject(); @@ -542,7 +544,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("A30", ratioNum); // 测试环境微信费率0.6 ecParams.put("A96", "1"); ecParams.put("A97", "是"); - ecParams.put("A100", "否"); + ecParams.put("A100", "是"); ecParams.put("A101", "中国境内"); ecParams.put("A102", platformName); ecParams.put("A103", "小发同城"); @@ -554,14 +556,22 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("A109", today.getDayOfMonth()); ecParams.put("B1", today.getYear()); ecParams.put("B3", "是"); + ecParams.put("B4", "是"); ecParams.put("B2", today.getMonthValue()); ecParams.put("B8", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); - ecParams.put("B9", StrUtil.subSufByLength(shopMchEntry.getSales_info(), 22)); + ecParams.put("B9", StrUtil.sub(shopMchEntry.getSales_info(), 0, 22)); ecParams.put("B10", isQy ? shopMchEntry.getBiz_license_company() : shopMchEntry.getAccount_holder_name()); ecParams.put("B14", isQy ? shopMchEntry.getBiz_license_number() : ""); ecParams.put("B16", isQy ? "是" : "否"); ecParams.put("B19", shopMchEntry.getOpenning_bank_code()); ecParams.put("B20", shopMchEntry.getAccount_number()); + + ecParams.put("B24", isQy ? shopMchEntry.getLegal_person_name() : shopMchEntry.getIndividual_id_name()); + ecParams.put("B25", isQy ? shopMchEntry.getLegal_person_id_number() : shopMchEntry.getIndividual_id_number()); + ecParams.put("B26", isQy ? shopMchEntry.getLegal_person_mobile() : shopMchEntry.getLogin_mobile()); + ecParams.put("B27", shopMchEntry.getContact_name()); + ecParams.put("B28", shopMchEntry.getEmail()); + ecParams.put("B31", shopMchEntry.getStore_name()); ecParams.put("B32", shopMchEntry.getContact_name()); ecParams.put("B33", shopMchEntry.getStore_address()); @@ -590,9 +600,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { reqBody.put("version", "3.0"); reqBody.put("req_data", reqData); - - String reqUrl = serverUrl + "/sit/api/v3/mms/open_api/ec/apply"; - if (isProd()) { + String reqUrl = serverUrl + "/api/v3/mms/open_api/ec/apply"; + if (isLklProd) { reqUrl = serverUrl + "/api/v3/mms/open_api/ec/apply"; } @@ -602,20 +611,26 @@ public class LakalaApiServiceImpl implements LakalaApiService { JSONObject header = new JSONObject(); header.put("Authorization", authorization); + String errMsg = ""; ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - return Pair.of(false, "商家入网申请电子合同:请求失败"); + errMsg = "商家入网申请电子合同失败:请求失败"; + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + return Pair.of(false, errMsg); } JSONObject respBody = response.getBody(); if (ObjectUtil.isNotEmpty(respBody) && !lklSuccessCode.equals(respBody.getStr("code"))) { - String errMsg = StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg"); - return Pair.of(false, "商家入网申请电子合同失败:" + errMsg); + errMsg = "商家入网申请电子合同失败:" + (StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg")); + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + return Pair.of(false, errMsg); } JSONObject respData = respBody.getJSONObject("resp_data"); if (respBody.getJSONObject("resp_data") == null) { - return Pair.of(false, "商家入网申请电子合同失败:返回数据有误"); + errMsg = "商家入网申请电子合同失败:返回数据有误"; + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + return Pair.of(false, errMsg); } // 商家入网申请电子合同处理数据 @@ -630,96 +645,15 @@ public class LakalaApiServiceImpl implements LakalaApiService { record.setResp_body(respBody.toString()); Boolean success = lklLedgerEcService.saveOrUpdateByMchId(record); if (!success) { - return Pair.of(false, "商家入网申请电子合同失败:本地数据保存失败"); + errMsg = "商家入网申请电子合同失败:数据保存失败"; + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + return Pair.of(false, errMsg); } return Pair.of(true, "商家入网申请电子合同成功"); } - /** - * 商户分账业务开通申请 - * - * @param paramsJSON - * @return - */ - @Override - public CommonResult applyLedgerMer(JSONObject paramsJSON) { - log.info("商户分账业务开通申请开始"); - - // TODO 判断是否已经申请过? - // 1. 配置初始化 - initLKLSDK(); - - //2. 装配数据 - V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); - req.setVersion("2.0"); - req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 - req.setOrgCode(orgCode); - req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));// 从进件申请返回的商户号 - req.setMerCupNo(paramsJSON.getStr("merCupNo")); // 从进件申请返回的商户号 - req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 - // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 - // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) - req.setSplitLowestRatio(new BigDecimal(ratio)); - String fileName = paramsJSON.getStr("splitEntrustFileName"); - req.setSplitEntrustFileName(fileName); - - // 分账结算委托书文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(paramsJSON.getStr("splitEntrustFile"))); - if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); - } - - String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); - req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; - - String domain = projectDomain; - if (isProd()) { - domain += "/api"; - } - // 给拉卡拉通知的回调地址 - String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; - req.setRetUrl(retUrl); - - paramsJSON.set("orderNo", req.getOrderNo()); - paramsJSON.set("version", "2.0"); - paramsJSON.set("ret_url", retUrl); - paramsJSON.set("org_code", orgCode); - paramsJSON.set("split_entrust_file_path", splitEntrustFilePath); - - try { - //3. 发送请求 - String responseStr = LKLSDK.httpPost(req); - - // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} - JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { - return CommonResult.failed(I18nUtil._("申请开通分账失败!")); - } - - if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - return CommonResult.failed(lakalaRespJSON.getStr("retMsg")); - } - - paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); - paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); - paramsJSON.set("audit_status_text", paramsJSON.get("remark")); - - paramsJSON.set("mch_id", paramsJSON.get("mchId")); - - // 新增数据 - // 将 JSON 对象的键名转换为下划线命名 - LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); - lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMember); - - return CommonResult.success(null, "提交成功,待审核中!"); - } catch (SDKException e) { - log.error("申请开通分账出错:", e); - throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); - } - } - @Override public Pair innerApplyLedgerMer(String merCupNo) { log.debug("商户分账业务开通申请开始"); @@ -758,7 +692,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String fileName = "小发同城分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); - // 分账结算委托书文件上传到拉卡拉服务器 + // TODO 分账结算委托书文件上传到拉卡拉服务器 JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(shopMchEntry.getContract_download_url())); if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { throw new ApiException(I18nUtil._("小发同城分账授权委托书上传失败!")); @@ -768,7 +702,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; String domain = projectDomain; - if (isProd()) { + if (isProdProject()) { domain += "/api"; } // 给拉卡拉通知的回调地址 @@ -792,7 +726,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { paramsJSON.put("split_entrust_file_name", req.getSplitEntrustFileName()); paramsJSON.put("split_entrust_file_path", splitEntrustFilePath); - try { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); @@ -834,16 +767,18 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public JSONObject applyLedgerMerEcNotify(HttpServletRequest request) { - log.info("商户入网电子合同申请回调通知开始"); + log.debug("商户入网电子合同申请回调通知开始"); // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); - log.info("商户入网电子合同申请回调返回参数:{}", requestBody); + log.debug("商户入网电子合同申请回调返回request body参数:{}", requestBody); + log.debug("商户入网电子合同申请回调返回authorization参数:{}", authorization); + String errMsg = "商户入网电子合同申请回调:"; boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { - log.info("商户入网电子合同申请回调:验签失败"); + log.error(errMsg + "验签失败"); return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); } @@ -858,21 +793,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { String ecNo = paramsJSON.getStr("ecNo"); String ecStatus = paramsJSON.getStr("ecStatus"); // COMPLETED if (ecStatus == null || !ecStatus.equals("COMPLETED")) { - log.info("商户入网电子合同申请状态尚未签署完成!"); - respData.put("retMsg", "入网电子合同尚未签署完成!"); + log.debug("商户入网电子合同申请状态尚未签署完成!"); + respData.put("retMsg", "入网电子合同尚未签署,请稍候!"); return respData; } if (ecApplyId == null || StrUtil.isBlank(ecNo)) { - log.info("商户入网电子合同申请回调:ecApplyId 为空"); + log.error("商户入网电子合同申请回调:ecApplyId 为空"); respData.put("retMsg", "ecApplyId 返回空值!"); return respData; } LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); if (lklLedgerEc == null) { - log.info("商户入网电子合同申请回调:未找到对应的入网电子合同记录"); - respData.put("retMsg", "未找到对应的入网电子合同记录!"); + log.error("商户入网电子合同申请回调:找不到对应入网lklLedgerEc电子合同记录"); + respData.put("retMsg", "找不到对应入网电子合同记录!"); return respData; } @@ -896,20 +831,23 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 更新本地数据状态和合同编号、合同名字 Boolean success = lklLedgerEcService.updateByApplyId(updRecord); if (success) { - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); - log.info("商户入网电子合同申请回调:处理成功"); - - // 更新商家入驻表的合同编号,和签署地址 + // 更新商家入驻表的合同编号,和签署地址,更改状态 shopMchEntryService.updateMerchEntryLklEcNo(lklLedgerEc.getMch_id(), ecNo, paramsJSON.getStr("ecName"), lklLedgerEc.getResult_url(), ecFileUrl); // TODO 商家电子合同签署完毕后,收到异步通知,触发拉卡拉商家进件(重要环节) // 下一步,等待拉卡拉系统审核,和人工审核,收到异步通知之后,触发1、e签宝的电子合同签署,2、新增分账接收方 Pair resultPair = lklTkService.registrationMerchant(lklLedgerEc.getMch_mobile(), ""); if (!resultPair.getFirst()) { - log.error("###商户入网电子合同签署通知回调:拉卡拉商家进件失败:", resultPair.getSecond()); - // return CommonResult.failed(resultPair.getSecond()); + errMsg += resultPair.getSecond(); + log.error(errMsg); + shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + respData.put("retMsg", errMsg); + return respData; } + + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.info("商户入网电子合同申请回调:处理成功"); } } @@ -939,8 +877,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { reqBody.put("version", "1.0"); reqBody.put("req_data", reqData); - String reqUrl = serverUrl + "/sit/api/v3/mms/open_api/ec/download"; - if (isProd()) { + String reqUrl = serverUrl + "/api/v3/mms/open_api/ec/download"; + if (isLklProd) { reqUrl = serverUrl + "/api/v3/mms/open_api/ec/download"; } @@ -990,6 +928,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { .concat(lklLedgerEc.getMch_mobile()).concat("/") .concat("signed").concat("/") .concat(ecApplyId.toString()).concat(".pdf"); + log.debug("拉卡拉电子合同保存地址:{}", cosFileName); // 上传到cos服务器 String cosFileUrl = ossService.uploadObject4OSS(file, cosFileName); @@ -1000,6 +939,94 @@ public class LakalaApiServiceImpl implements LakalaApiService { return cosFileUrl; } + /** + * 商户分账业务开通申请 + * + * @param paramsJSON + * @return + */ + @Override + public CommonResult applyLedgerMer(JSONObject paramsJSON) { + log.debug("商户分账业务开通申请1开始"); + + // TODO 判断是否已经申请过? + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); + req.setVersion("2.0"); + req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 + req.setOrgCode(orgCode); + req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));// 从进件申请返回的商户号 + req.setMerCupNo(paramsJSON.getStr("merCupNo")); // 从进件申请返回的商户号 + req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 + // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 + // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) + req.setSplitLowestRatio(new BigDecimal(ratio)); + String fileName = paramsJSON.getStr("splitEntrustFileName"); + req.setSplitEntrustFileName(fileName); + + // 分账结算委托书文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(paramsJSON.getStr("splitEntrustFile"))); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); + } + + String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); + req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + + // 正式上线的时候,调整 api 地址 + String domain = projectDomain; + if (isProdProject()) { + domain += "/api"; + } + // 给拉卡拉通知的回调地址 + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; + req.setRetUrl(retUrl); + + paramsJSON.set("orderNo", req.getOrderNo()); + paramsJSON.set("version", "2.0"); + paramsJSON.set("ret_url", retUrl); + paramsJSON.set("org_code", orgCode); + paramsJSON.set("split_entrust_file_path", splitEntrustFilePath); + + String errMsg = "商户分账业务开通申请:"; + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + + // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { + return CommonResult.failed(I18nUtil._("申请开通分账失败!")); + } + + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + return CommonResult.failed(lakalaRespJSON.getStr("retMsg")); + } + + paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); + paramsJSON.set("audit_status_text", paramsJSON.get("remark")); + + paramsJSON.set("mch_id", paramsJSON.get("mchId")); + + // 新增数据 + // 将 JSON 对象的键名转换为下划线命名 + LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); + lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMember); + + return CommonResult.success(null, "提交成功,待审核中!"); + } catch (SDKException e) { + errMsg += e.getMessage(); + log.error(errMsg); + shopMchEntryService.updateMerchEntryApprovalByMchId(paramsJSON.getLong("mchId"), paramsJSON.getStr("mchMobile"), CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); + } + } + /** * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 @@ -1009,37 +1036,50 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public JSONObject applyLedgerMerNotify(HttpServletRequest request) { - log.info("商户分账申请业务异步通知开始"); + log.debug("商户分账申请业务异步回调通知开始"); // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); - log.info("商户分账申请业务回调返回参数:{}", requestBody); + log.debug("商户分账申请业务异步回调返回request body参数:{}", requestBody); + log.debug("商户分账申请业务异步回调返回authorization参数:{}", authorization); boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { - log.info("商户分账申请业务回调:验签失败"); - return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + log.error("商户分账申请业务回调:验签失败"); + return JSONUtil.createObj().put("retCode", "OP90002").put("retMsg", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); + String errMsg = "商户分账申请业务回调:"; JSONObject respData = new JSONObject(); respData.put("retCode", "OP90003"); respData.put("retMsg", "响应处理失败!"); if (paramsJSON != null) { String applyId = paramsJSON.getStr("applyId"); - if (StrUtil.isBlank(applyId)) { - log.info("商户分账申请业务回调:applyId为空"); - respData.put("retMsg", "applyId为空!"); + String auditStatus = paramsJSON.getStr("auditStatus"); + if (StrUtil.isBlank(applyId) || StrUtil.isBlank(auditStatus)) { + errMsg += "缺少返回必要参数"; + log.error(errMsg + ":applyId={}, auditStatus={}", applyId, auditStatus); + + respData.put("retMsg", errMsg); return respData; } - if (lklLedgerMemberService.getByApplyId(applyId, CommonConstant.Enable) != null) { + //auditStatus:1:通过,2拒绝 + if (!auditStatus.equals("1")) { + respData.put("retMsg", "商户分账申请被驳回!"); + return respData; + } + + LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByApplyId(applyId, CommonConstant.Enable); + if (lklLedgerMember != null) { respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); - log.info("商户分账申请业务回调:已处理成功,不需再重新处理"); + respData.put("retMsg", "商户分账申请已处理成功!"); + log.debug("商户分账申请业务回调:已处理成功,不需再重新处理"); + return respData; } // 更改本地分账记录状态数据 @@ -1055,24 +1095,27 @@ public class LakalaApiServiceImpl implements LakalaApiService { ); if (success) { - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); - log.info("商户分账申请业务回调:处理成功"); - // 重要注:商户分账申请业务成功后,同时也会新增接收方,这时系统绑定接收方(平台方和代理商),绑定之前,要判断是否已经绑定过了? JSONObject bindParamsJSON = new JSONObject(); bindParamsJSON.put("merInnerNo", paramsJSON.getStr("merInnerNo")); bindParamsJSON.put("merCupNo", merCupNo); Pair bindResult = innerApplyLedgerMerReceiverBind(bindParamsJSON); - if (bindResult.getFirst()) { - log.info("商户分账申请业务回调:", bindResult.getSecond()); - } else { - log.error("商户分账申请业务回调:", bindResult.getSecond()); + if (!bindResult.getFirst()) { + errMsg += bindResult.getSecond(); + log.error("商户{}预绑定接收方出错:{}", merCupNo, bindResult.getSecond()); + + shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerMember.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + respData.put("retMsg", "操作成功!"); + return respData; } - // 更新商家的hasApplySplit状态=1 - lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 1, 0, 0); + // 更新商家的hasApplySplit状态=1;has_esigned=1 + lklLedgerMemberService.updateMulStatus(merCupNo, "", 1, 1, 0, 0); + respData.put("retCode", lklSuccessCode); + respData.put("retMsg", "操作成功!"); + log.debug("商户分账申请业务回调:处理成功"); + return respData; } } @@ -1231,8 +1274,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(paramsJSON.getStr("entrustFile")); // 这个是 url 地址,不是 base64 字节码 req.setEntrustFileName(fileName); + // 正式上线的时候,调整 api 地址 String domain = projectDomain; - if (isProd()) { + if (isProdProject()) { domain += "/api"; } // 给拉卡拉通知的回调地址 @@ -1263,7 +1307,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + if (lakalaRespJSON == null) { + throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + } + + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); } @@ -1275,7 +1323,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { LklLedgerMerReceiverBind lklLedgerMerReceiverBind = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMerReceiverBind.class); lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(lklLedgerMerReceiverBind); - return CommonResult.success(lklLedgerMerReceiverBind, "提交成功,待审核中!"); } catch (SDKException e) { log.error("分账绑定关系申请失败:", e); @@ -1342,7 +1389,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setEntrustFileName(entrustFileName); String domain = projectDomain; - if (isProd()) { + if (isProdProject()) { domain += "/api"; } // 给拉卡拉通知的回调地址 @@ -1415,15 +1462,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { - log.debug("分账绑定关系申请业务异步通知开始"); + log.debug("分账商家绑定接收方异步回调通知开始"); // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); - log.debug("分账绑定关系申请业务回调返回参数:{}", requestBody); + log.debug("分账商家绑定接收方异步回调返回request body参数:{}", requestBody); + log.debug("分账商家绑定接收方异步回调返回authorization参数:{}", authorization); boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { - return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + return JSONUtil.createObj().put("retCode", "OP90002").put("retMsg", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); @@ -1433,7 +1481,23 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (paramsJSON != null) { String merCupNo = paramsJSON.getStr("merCupNo"); - Boolean success = lklLedgerMerReceiverBindService.updateAuditResult(paramsJSON.getStr("applyId"), + String applyId = paramsJSON.getStr("applyId"); + String auditStatus = paramsJSON.getStr("auditStatus"); + if (StrUtil.isBlank(merCupNo) || StrUtil.isBlank(applyId) || StrUtil.isBlank(auditStatus)) { + String errMsg = "缺少返回必要参数"; + log.error(errMsg + ":applyId={}, applyId={}, auditStatus={}", merCupNo, applyId, auditStatus); + + respData.put("retMsg", errMsg); + return respData; + } + + //auditStatus:1:通过,2拒绝 + if (!auditStatus.equals("1")) { + respData.put("retMsg", "绑定接收方被驳回!"); + return respData; + } + + Boolean success = lklLedgerMerReceiverBindService.updateAuditResult(applyId, paramsJSON.getStr("merInnerNo"), merCupNo, paramsJSON.getStr("receiverNo"), @@ -1443,8 +1507,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { paramsJSON.getStr("auditStatusText"), paramsJSON.getStr("remark")); if (success) { - respData.put("retCode", lklSuccessCode); - // 更改商家的状态 has_bind_receiver 状态=1 lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 0, 0, 1); @@ -1455,16 +1517,19 @@ public class LakalaApiServiceImpl implements LakalaApiService { String mchMobile = shopEntry.getLogin_mobile(); Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(mchMobile); if (retPair.getFirst() > 0) { + // 2025-05-17暂停e签宝电子合同生成流程 // 更改合同记录表的店铺id - esignContractService.updateContractStoreId(mchMobile, retPair.getFirst()); + // esignContractService.updateContractStoreId(mchMobile, retPair.getFirst()); // 填充合同模版表的店铺Id - esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); + // esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); // 店铺创建状态已完成 shopMchEntryService.updateMerchEntryStoreStatus(mchMobile, CommonConstant.Enable); } } + respData.put("retCode", lklSuccessCode); respData.put("retMsg", "操作成功!"); + return respData; } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java index b944cf6b..31a0a538 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -146,7 +146,7 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); if (StrUtil.isNotBlank(mchMobile)) { - updateWrapper.eq("mch_mobile", mchMobile); + updateWrapper.eq("contact_mobile", mchMobile); } if (StrUtil.isNotBlank(merCupNo)) { updateWrapper.eq("mer_cup_no", merCupNo); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 59720908..d25d9868 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -194,6 +194,8 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); + ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, requestBody, JSONObject.class); if (ObjectUtil.isEmpty(updResponse) || updResponse.getStatusCode() != HttpStatus.OK || ObjectUtil.isEmpty(updResponse.getBody())) { @@ -221,13 +230,20 @@ public class LklTkServiceImpl { JSONObject header = new JSONObject(); header.put("Authorization", authorization); - String ocrUrlPath = isProd() ? "/registration/ocr/result" : "/sit/htkregistration/ocr/result"; + JSONObject ocrRequestBody = new JSONObject(); ocrRequestBody.put("batchNo", batchNo); ocrRequestBody.put("imgType", imgType); logger.info("ocr请求参数:{}", ocrRequestBody); + + String urlPath = "/sit/htkregistration/ocr/result"; + if (isLklProd) { + // 生产环境启用 + urlPath = "/registration/ocr/result"; + } + try { - ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(ocrUrlPath), header, ocrRequestBody, JSONObject.class); + ResponseEntity ocrResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, ocrRequestBody, JSONObject.class); if (ObjectUtil.isEmpty(ocrResponse) || ocrResponse.getStatusCode() != HttpStatus.OK || ObjectUtil.isEmpty(ocrResponse.getBody())) { @@ -264,7 +280,14 @@ public class LklTkServiceImpl { formData.put("client_id", clientId); formData.put("client_secret", clientSecret); - String response = RestTemplateHttpUtil.sendPostFormData(buildLklTkUrl("/sit/htkauth/oauth/token"), null, formData, String.class); + String urlPath = "/sit/htkauth/oauth/token"; + if (isLklProd) { + // 生产环境启用 + urlPath = "/auth/oauth/token"; + } + + + String response = RestTemplateHttpUtil.sendPostFormData(buildLklTkUrl(urlPath), null, formData, String.class); if (ObjectUtil.isEmpty(response)) { return ""; } @@ -298,7 +321,7 @@ public class LklTkServiceImpl { header.put("Authorization", getLklTkAuthorization()); // 获取商家入驻信息,组成请求参数 - ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, bizLicenseNumber, CommonConstant.MCH_APPR_STA_PASS, CommonConstant.MCH_APPR_STA_LKL_PADDING); + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, bizLicenseNumber); if (ObjectUtil.isEmpty(shopMchEntry)) { return Pair.of(false, "商家入驻信息不存在"); } @@ -401,7 +424,6 @@ public class LklTkServiceImpl { } } - // 费率和设备、活动 JSONObject bizContent = new JSONObject(); bizContent.put("activityId", 687); @@ -465,7 +487,14 @@ public class LklTkServiceImpl { formData.put("attchments", attachments); // 附件文件相关结束 - String urlPath = isProd() ? "/registration/merchant" : "/sit/htkregistration/merchant"; + String urlPath = "/sit/htkregistration/merchant"; + if (isLklProd) { + // 生产环境启用 + urlPath = "/registration/merchant"; + } + + +// String urlPath = isProd() ? "/registration/merchant" : "/sit/htkregistration/merchant"; try { logger.info("进件请求参数:{}", JSONUtil.toJsonStr(formData)); @@ -497,7 +526,7 @@ public class LklTkServiceImpl { } /** - * 拉卡拉进件异步通知 + * (重要)拉卡拉进件异步通知 * * @param request * @return @@ -533,10 +562,15 @@ public class LklTkServiceImpl { // 逻辑处理 JSONObject dataJSON = JSONUtil.parseObj(data); - if (dataJSON.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo"))) { + if (dataJSON.isEmpty() || StrUtil.isBlank(dataJSON.getStr("externalCustomerNo")) || StrUtil.isBlank(dataJSON.getStr("status"))) { return new JSONObject().set("code", "500").set("message", "参数解析出错"); } + String auditStatus = dataJSON.getStr("status"); + if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) { + return new JSONObject().set("code", "500").set("message", "返回审核状态有误"); + } + // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 @@ -551,24 +585,40 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "500").set("message", "更新商户号失败"); } - logger.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###"); - // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 - Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(shopMchEntry.getLogin_mobile(), ""); - if (!genSuccess) { - logger.error("###商家入驻电子合同生成失败###"); + // 备注:RMK 采用拉卡拉的入网电子合同签署流程,暂停e签宝的电子合同生成流程 +// logger.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###"); +// // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 +// Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(shopMchEntry.getLogin_mobile(), ""); +// if (!genSuccess) { +// logger.error("###商家入驻电子合同生成失败###"); +// } +// +// // 1、发起E签宝合同签署;签署完成之后,生成分账盖章协议书,下一步才能申请分账功能权限; +// Pair resPair = esignContractService.innerSignFlowCreateByFile(shopMchEntry.getLogin_mobile()); +// if (!resPair.getFirst()) { +// logger.error("###商家发起电子签名失败:{}###", resPair.getSecond()); +// } + + // 给商家申请分账功能使用;务必检查是否申请过?申请过忽略 + if (success && StrUtil.isNotBlank(shopMchEntry.getContract_download_url())) { + + // 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略 + // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 + Pair retPair = lakalaApiService.innerApplyLedgerMer(shopMchEntry.getLkl_mer_cup_no()); + if (!retPair.getFirst()) { + logger.error("商家申请分账功能失败:{}", retPair.getSecond()); + } + + // 更新商家的hasEsigned状态=1 +// lklLedgerMemberService.updateMulStatus("", shopMchEntry.getLogin_mobile(), 1, 0, 0, 0); + + // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 + Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); + if (!genSuccess) { + logger.error("申请分账接收方失败"); + } } - // 1、发起E签宝合同签署;签署完成之后,生成分账盖章协议书,下一步才能申请分账功能权限; - Pair resPair = esignContractService.innerSignFlowCreateByFile(shopMchEntry.getLogin_mobile()); - if (!resPair.getFirst()) { - logger.error("###商家发起电子签名失败:{}###", resPair.getSecond()); - } - - // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 - genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); - if (!genSuccess) { - logger.error("###申请分账接收方失败###"); - } return new JSONObject().set("code", "200").set("message", "成功"); } @@ -603,9 +653,6 @@ public class LklTkServiceImpl { countryName = areaNames[2]; } - String urlPath = isProd() ? "/registration/organization" : "/sit/htkregistration/organization"; - urlPath = isBankArea ? urlPath + "/bank" : urlPath; // 银行地区 - String authorization = getLklTkAuthorization(); if (StrUtil.isBlank(authorization)) { logger.error("获取拉卡拉token失败"); @@ -615,6 +662,13 @@ public class LklTkServiceImpl { JSONObject header = new JSONObject(); header.put("Authorization", getLklTkAuthorization()); + String urlPath = "/sit/htkregistration/organization"; + if (isLklProd) { + // 生产环境启用 + urlPath = "/registration/organization"; + } + urlPath = isBankArea ? urlPath + "/bank" : urlPath; // 银行地区 + // 省份列表 ResponseEntity response = RestTemplateHttpUtil.sendGetWithHeader(buildLklTkUrl(urlPath + "/1"), header, JSONArray.class); @@ -702,7 +756,6 @@ public class LklTkServiceImpl { JSONObject header = new JSONObject(); header.put("Authorization", getLklTkAuthorization()); - String updUrlPath = isProd() ? "/registration/file/base/upload" : "/sit/htkregistration/file/base/upload"; String fileBase64 = UploadUtil.fileUrlToBase64(fileUrl); if (StrUtil.isBlank(fileBase64)) { logger.error("文件转换失败"); @@ -716,8 +769,14 @@ public class LklTkServiceImpl { requestBody.put("sourcechnl", "0"); // 来源: 0:PC,1:安卓,2:IOS requestBody.put("isOcr", "true"); + String urlPath = "/sit/htkregistration/file/base/upload"; + if (isLklProd) { + // 生产环境启用 + urlPath = "/registration/file/base/upload"; + } + try { - ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(updUrlPath), header, requestBody, JSONObject.class); + ResponseEntity updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, requestBody, JSONObject.class); if (ObjectUtil.isEmpty(updResponse) || updResponse.getStatusCode() != HttpStatus.OK) { logger.error("上传文件返回值有误"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 6a46aa13..16c64804 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -190,5 +190,15 @@ public interface ShopMchEntryService { */ Boolean updateMerchEntryLklEcNo(Long id, String lklEcNo, String lklEcName, String lklEcResultUrl, String ecDownloadUrl); + /** + * 更新商家入驻申请的审批状态和审批备注 + * + * @param mchId 商家入驻申请 ID,mchId和mchMobile至少必填一个 + * @param mchMobile 商家注册的手机号 mchId和mchMobile至少必填一个 + * @param approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核; + * @param approvalRemark 审批备注 + * @return + */ + Boolean updateMerchEntryApprovalByMchId(Long mchId, String mchMobile, Integer approvalStatus, String approvalRemark); } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 0def9e67..9458464f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -828,6 +828,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + if (ObjectUtil.isNotEmpty(mchId)) { + updateWrapper.eq("id", mchId); + } + if (StrUtil.isNotBlank(mchMobile)) { + updateWrapper.eq("login_mobile", mchMobile); + } + + if (ObjectUtil.isNotEmpty(approvalStatus)) { + updateWrapper.set("approval_status", approvalStatus); + } + + if (StrUtil.isNotBlank(approvalRemark)) { + updateWrapper.set("approval_remark", approvalRemark); + } return update(updateWrapper); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java index 0a4fe6df..84310272 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java @@ -3008,7 +3008,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl Date: Sun, 18 May 2025 11:09:33 +0800 Subject: [PATCH 29/39] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E5=A4=84=E7=90=86=EF=BC=8C=E5=8A=A0=E4=B8=8A=E4=BA=8B=E5=8A=A1?= =?UTF-8?q?=E5=A4=84=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/LakalaApiServiceImpl.java | 253 ++++++++++-------- .../lakala/service/impl/LklTkServiceImpl.java | 28 +- .../src/main/resources/bootstrap-local.yml | 2 +- .../src/main/resources/bootstrap-prod.yml | 2 +- 4 files changed, 159 insertions(+), 126 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 49a2da64..6edbdc51 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -43,6 +43,7 @@ import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; @@ -83,15 +84,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签) @Value("${lakala.org_code}") private String orgCode; - @Value("${lakala.tk.ratio}") - private String ratio; + @Value("${lakala.tk.split_lowest_ratio}") + private String splitLowestRatio; @Value("${project.domain}") private String projectDomain; @Value("${spring.profiles.active}") private String profile; @Value("${lakala.is_prod}") private Boolean isLklProd; - @Value("#{accountBaseConfigService.getConfig('tengxun_default_dir')}") private String TENGXUN_DEFAULT_DIR; @@ -588,7 +588,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { ecParams.put("E2", "小发同城平台商户合作协议"); ecParams.put("E3", "2"); ecParams.put("E5", platformName); - ecParams.put("E6", ratio); + ecParams.put("E6", splitLowestRatio); ecParams.put("E7", signDate); ecParams.put("E8", shopMchEntry.getAccount_holder_name()); @@ -654,6 +654,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { } + /** + * 商户分账业务开通申请 + * + * @param merCupNo + * @return + */ @Override public Pair innerApplyLedgerMer(String merCupNo) { log.debug("商户分账业务开通申请开始"); @@ -687,7 +693,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) - req.setSplitLowestRatio(new BigDecimal(ratio)); + req.setSplitLowestRatio(new BigDecimal(splitLowestRatio)); req.setEleContractNo(shopMchEntry.getLkl_ec_no()); String fileName = "小发同城分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); @@ -765,6 +771,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { * @param request * @return */ + @Transactional @Override public JSONObject applyLedgerMerEcNotify(HttpServletRequest request) { log.debug("商户入网电子合同申请回调通知开始"); @@ -779,14 +786,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { log.error(errMsg + "验签失败"); - return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + return JSONUtil.createObj().set("code", "OP90002").set("retMsg", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); JSONObject respData = new JSONObject(); - respData.put("retCode", "OP90003"); - respData.put("retMsg", "系统处理失败!"); + respData.put("code", "FAIL"); + respData.put("message", "处理失败!"); if (paramsJSON != null) { Long ecApplyId = paramsJSON.getLong("ecApplyId"); @@ -794,26 +801,27 @@ public class LakalaApiServiceImpl implements LakalaApiService { String ecStatus = paramsJSON.getStr("ecStatus"); // COMPLETED if (ecStatus == null || !ecStatus.equals("COMPLETED")) { log.debug("商户入网电子合同申请状态尚未签署完成!"); - respData.put("retMsg", "入网电子合同尚未签署,请稍候!"); + respData.put("message", "入网电子合同尚未签署,请稍候!"); return respData; } if (ecApplyId == null || StrUtil.isBlank(ecNo)) { log.error("商户入网电子合同申请回调:ecApplyId 为空"); - respData.put("retMsg", "ecApplyId 返回空值!"); + respData.put("message", "ecApplyId 返回空值!"); return respData; } LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); if (lklLedgerEc == null) { log.error("商户入网电子合同申请回调:找不到对应入网lklLedgerEc电子合同记录"); - respData.put("retMsg", "找不到对应入网电子合同记录!"); + respData.put("message", "找不到对应入网电子合同记录!"); +// throw new ApiException("找不到对应入网电子合同记录!"); return respData; } if ("COMPLETED".equals(lklLedgerEc.getEc_status())) { - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); + respData.put("code", "SUCCESS"); + respData.put("message", "操作成功!"); log.info("商户入网电子合同申请回调:已处理成功,不需再重新处理"); return respData; } @@ -839,19 +847,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { Pair resultPair = lklTkService.registrationMerchant(lklLedgerEc.getMch_mobile(), ""); if (!resultPair.getFirst()) { errMsg += resultPair.getSecond(); - log.error(errMsg); +// log.error(errMsg); shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); - respData.put("retMsg", errMsg); - return respData; +// respData.put("message", errMsg); + throw new ApiException(errMsg); +// return respData; } - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); + respData.put("code", "SUCCESS"); + respData.put("message", "操作成功!"); log.info("商户入网电子合同申请回调:处理成功"); + return respData; } } - return respData; + throw new ApiException("商户入网电子合同申请回调:处理失败!"); } /** @@ -947,84 +957,91 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public CommonResult applyLedgerMer(JSONObject paramsJSON) { - log.debug("商户分账业务开通申请1开始"); - - // TODO 判断是否已经申请过? - // 1. 配置初始化 - initLKLSDK(); - - //2. 装配数据 - V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); - req.setVersion("2.0"); - req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 - req.setOrgCode(orgCode); - req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));// 从进件申请返回的商户号 - req.setMerCupNo(paramsJSON.getStr("merCupNo")); // 从进件申请返回的商户号 - req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 - // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 - // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) - req.setSplitLowestRatio(new BigDecimal(ratio)); - String fileName = paramsJSON.getStr("splitEntrustFileName"); - req.setSplitEntrustFileName(fileName); - - // 分账结算委托书文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(paramsJSON.getStr("splitEntrustFile"))); - if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); + Pair resultPair = innerApplyLedgerMer(paramsJSON.getStr("merCupNo")); + if (!resultPair.getFirst()) { + return CommonResult.failed(resultPair.getSecond()); } - String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); - req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + return CommonResult.success(); - // 正式上线的时候,调整 api 地址 - String domain = projectDomain; - if (isProdProject()) { - domain += "/api"; - } - // 给拉卡拉通知的回调地址 - String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; - req.setRetUrl(retUrl); - - paramsJSON.set("orderNo", req.getOrderNo()); - paramsJSON.set("version", "2.0"); - paramsJSON.set("ret_url", retUrl); - paramsJSON.set("org_code", orgCode); - paramsJSON.set("split_entrust_file_path", splitEntrustFilePath); - - String errMsg = "商户分账业务开通申请:"; - - try { - //3. 发送请求 - String responseStr = LKLSDK.httpPost(req); - - // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} - JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { - return CommonResult.failed(I18nUtil._("申请开通分账失败!")); - } - - if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - return CommonResult.failed(lakalaRespJSON.getStr("retMsg")); - } - - paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); - paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); - paramsJSON.set("audit_status_text", paramsJSON.get("remark")); - - paramsJSON.set("mch_id", paramsJSON.get("mchId")); - - // 新增数据 - // 将 JSON 对象的键名转换为下划线命名 - LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); - lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMember); - - return CommonResult.success(null, "提交成功,待审核中!"); - } catch (SDKException e) { - errMsg += e.getMessage(); - log.error(errMsg); - shopMchEntryService.updateMerchEntryApprovalByMchId(paramsJSON.getLong("mchId"), paramsJSON.getStr("mchMobile"), CommonConstant.MCH_APPR_STA_NOPASS, errMsg); - throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); - } +// log.debug("商户分账业务开通申请1开始"); +// +// // TODO 判断是否已经申请过? +// // 1. 配置初始化 +// initLKLSDK(); +// +// //2. 装配数据 +// V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest(); +// req.setVersion("2.0"); +// req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 +// req.setOrgCode(orgCode); +// req.setMerInnerNo(paramsJSON.getStr("merInnerNo"));// 从进件申请返回的商户号 +// req.setMerCupNo(paramsJSON.getStr("merCupNo")); // 从进件申请返回的商户号 +// req.setContactMobile(paramsJSON.getStr("contactMobile")); // 商户入驻注册的手机号 +// // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 +// // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) +// req.setSplitLowestRatio(new BigDecimal(splitLowestRatio)); +// String fileName = paramsJSON.getStr("splitEntrustFileName"); +// req.setSplitEntrustFileName(fileName); +// +// // 分账结算委托书文件上传到拉卡拉服务器 +// JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(paramsJSON.getStr("splitEntrustFile"))); +// if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { +// throw new ApiException(I18nUtil._("分账结算委托书上传失败!")); +// } +// +// String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); +// req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; +// +// // 正式上线的时候,调整 api 地址 +// String domain = projectDomain; +// if (isProdProject()) { +// domain += "/api"; +// } +// // 给拉卡拉通知的回调地址 +// String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; +// req.setRetUrl(retUrl); +// +// paramsJSON.set("orderNo", req.getOrderNo()); +// paramsJSON.set("version", "2.0"); +// paramsJSON.set("ret_url", retUrl); +// paramsJSON.set("org_code", orgCode); +// paramsJSON.set("split_entrust_file_path", splitEntrustFilePath); +// +// String errMsg = "商户分账业务开通申请:"; +// +// try { +// //3. 发送请求 +// String responseStr = LKLSDK.httpPost(req); +// +// // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} +// JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); +// if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { +// return CommonResult.failed(I18nUtil._("申请开通分账失败!")); +// } +// +// if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { +// return CommonResult.failed(lakalaRespJSON.getStr("retMsg")); +// } +// +// paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); +// paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); +// paramsJSON.set("audit_status_text", paramsJSON.get("remark")); +// +// paramsJSON.set("mch_id", paramsJSON.get("mchId")); +// +// // 新增数据 +// // 将 JSON 对象的键名转换为下划线命名 +// LklLedgerMember lklLedgerMember = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); +// lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMember); +// +// return CommonResult.success(null, "提交成功,待审核中!"); +// } catch (SDKException e) { +// errMsg += e.getMessage(); +// log.error(errMsg); +// shopMchEntryService.updateMerchEntryApprovalByMchId(paramsJSON.getLong("mchId"), paramsJSON.getStr("mchMobile"), CommonConstant.MCH_APPR_STA_NOPASS, errMsg); +// throw new ApiException(I18nUtil._("商家申请开通分账出错!"), e); +// } } /** @@ -1034,6 +1051,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { * @param request * @return */ + @Transactional @Override public JSONObject applyLedgerMerNotify(HttpServletRequest request) { log.debug("商户分账申请业务异步回调通知开始"); @@ -1047,15 +1065,15 @@ public class LakalaApiServiceImpl implements LakalaApiService { boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { log.error("商户分账申请业务回调:验签失败"); - return JSONUtil.createObj().put("retCode", "OP90002").put("retMsg", "验签失败!"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); String errMsg = "商户分账申请业务回调:"; JSONObject respData = new JSONObject(); - respData.put("retCode", "OP90003"); - respData.put("retMsg", "响应处理失败!"); + respData.put("code", "FAIL"); + respData.put("message", "处理失败!"); if (paramsJSON != null) { String applyId = paramsJSON.getStr("applyId"); @@ -1064,20 +1082,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { errMsg += "缺少返回必要参数"; log.error(errMsg + ":applyId={}, auditStatus={}", applyId, auditStatus); - respData.put("retMsg", errMsg); + respData.put("message", errMsg); return respData; } //auditStatus:1:通过,2拒绝 if (!auditStatus.equals("1")) { - respData.put("retMsg", "商户分账申请被驳回!"); + respData.put("message", "商户分账申请被驳回!"); return respData; } LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByApplyId(applyId, CommonConstant.Enable); if (lklLedgerMember != null) { - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "商户分账申请已处理成功!"); + respData.put("code", "SUCCESS"); + respData.put("message", "商户分账申请已处理成功!"); log.debug("商户分账申请业务回调:已处理成功,不需再重新处理"); return respData; } @@ -1105,21 +1123,22 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.error("商户{}预绑定接收方出错:{}", merCupNo, bindResult.getSecond()); shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerMember.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); - respData.put("retMsg", "操作成功!"); - return respData; +// respData.put("message", errMsg); + throw new ApiException(errMsg); +// return respData; } // 更新商家的hasApplySplit状态=1;has_esigned=1 lklLedgerMemberService.updateMulStatus(merCupNo, "", 1, 1, 0, 0); - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); + respData.put("code", "SUCCESS"); + respData.put("message", "操作成功!"); log.debug("商户分账申请业务回调:处理成功"); return respData; } } - return respData; + throw new ApiException("商户分账申请业务回调:操作失败!"); } /** @@ -1460,6 +1479,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { * @param request * @return */ + @Transactional @Override public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { log.debug("分账商家绑定接收方异步回调通知开始"); @@ -1471,13 +1491,13 @@ public class LakalaApiServiceImpl implements LakalaApiService { boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { - return JSONUtil.createObj().put("retCode", "OP90002").put("retMsg", "验签失败!"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); JSONObject respData = new JSONObject(); - respData.put("retCode", "OP90003"); - respData.put("retMsg", "响应处理失败!"); + respData.put("code", "FAIL"); + respData.put("message", "处理失败!"); if (paramsJSON != null) { String merCupNo = paramsJSON.getStr("merCupNo"); @@ -1487,13 +1507,13 @@ public class LakalaApiServiceImpl implements LakalaApiService { String errMsg = "缺少返回必要参数"; log.error(errMsg + ":applyId={}, applyId={}, auditStatus={}", merCupNo, applyId, auditStatus); - respData.put("retMsg", errMsg); + respData.put("message", errMsg); return respData; } //auditStatus:1:通过,2拒绝 if (!auditStatus.equals("1")) { - respData.put("retMsg", "绑定接收方被驳回!"); + respData.put("message", "绑定接收方被驳回!"); return respData; } @@ -1524,16 +1544,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { // esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); // 店铺创建状态已完成 shopMchEntryService.updateMerchEntryStoreStatus(mchMobile, CommonConstant.Enable); + } else { + throw new ApiException("商家绑定接收方:创建初始化店铺失败!"); } } - respData.put("retCode", lklSuccessCode); - respData.put("retMsg", "操作成功!"); + respData.put("code", "SUCCESS"); + respData.put("message", "操作成功!"); return respData; } } - return respData; + throw new ApiException("商家绑定接收方:操作失败!"); + +// throw new ServiceException("分账绑定关系申请回调失败!"); +// return respData; } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 7d2089db..4414aea6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -18,6 +18,7 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.api.ResultCode; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.domain.UserDto; +import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.utils.RestTemplateHttpUtil; import com.suisung.mall.common.utils.StringUtils; @@ -37,6 +38,7 @@ import org.springframework.data.util.Pair; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; @@ -531,6 +533,7 @@ public class LklTkServiceImpl { * @param request * @return */ + @Transactional public JSONObject registrationMerchantNotify(HttpServletRequest request) { logger.debug("拉卡拉进件异步通知开始"); @@ -538,24 +541,24 @@ public class LklTkServiceImpl { String requestBody = LakalaUtil.getBody(request); logger.debug("拉卡拉进件异步通知返回参数:{}", requestBody); if (StrUtil.isBlank(requestBody)) { - return new JSONObject().set("code", "500").set("message", "返回参数为空"); + return new JSONObject().set("code", "FAIL").set("message", "返回参数为空"); } JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody); if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) { - return new JSONObject().set("code", "500").set("message", "参数格式有误,无法解析"); + return new JSONObject().set("code", "FAIL").set("message", "参数格式有误,无法解析"); } String srcData = reqBodyJSON.getStr("data"); if (StrUtil.isBlank(srcData)) { - return new JSONObject().set("code", "500").set("message", "关键参数为空值"); + return new JSONObject().set("code", "FAIL").set("message", "关键参数为空值"); } // 公钥解密出来的数据 String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false); String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData); if (StrUtil.isBlank(data)) { - return new JSONObject().set("code", "500").set("message", "密文解密出错!"); + return new JSONObject().set("code", "FAIL").set("message", "密文解密出错!"); } logger.debug("拉卡拉进件异步通知data解密成功,开始处理逻辑"); @@ -568,7 +571,7 @@ public class LklTkServiceImpl { String auditStatus = dataJSON.getStr("status"); if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) { - return new JSONObject().set("code", "500").set("message", "返回审核状态有误"); + return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误"); } // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 @@ -577,12 +580,13 @@ public class LklTkServiceImpl { ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo); if (ObjectUtil.isEmpty(shopMchEntry)) { logger.error("拉卡拉进件异步通知:返回的内部商户号:{} 入驻信息不存在!", merInnerNo); - return new JSONObject().set("code", "500").set("message", "内部商户号:" + merInnerNo + " 入驻信息不存在"); + return new JSONObject().put("code", "FAIL").put("message", "内部商户号:" + merInnerNo + " 入驻信息不存在"); } Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, data); if (!success) { - return new JSONObject().set("code", "500").set("message", "更新商户号失败"); +// return new JSONObject().set("code", "FAIL").set("message", "更新商户号失败"); + throw new ApiException("更新商户号失败"); } // 备注:RMK 采用拉卡拉的入网电子合同签署流程,暂停e签宝的电子合同生成流程 @@ -606,7 +610,9 @@ public class LklTkServiceImpl { // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 Pair retPair = lakalaApiService.innerApplyLedgerMer(shopMchEntry.getLkl_mer_cup_no()); if (!retPair.getFirst()) { - logger.error("商家申请分账功能失败:{}", retPair.getSecond()); + String message = "商家申请分账功能失败:" + retPair.getSecond(); + logger.error(message); + throw new ApiException(message); } // 更新商家的hasEsigned状态=1 @@ -616,11 +622,13 @@ public class LklTkServiceImpl { Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); if (!genSuccess) { logger.error("申请分账接收方失败"); + throw new ApiException("申请分账接收方失败"); } + + return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); } - - return new JSONObject().set("code", "200").set("message", "成功"); + throw new ApiException("进件回调处理失败"); } /** diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 9ad43920..f79745fd 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -169,7 +169,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 - ratio: 70.00 + split_lowest_ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 25a4154f..841800e5 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -196,7 +196,7 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 user_no: 29153396 - ratio: 70.00 + split_lowest_ratio: 70.00 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt notify_pub_key_path: payKey/lakala/dev/tk_notify_public_key.txt From 42dc03453db01a1a559824f12c9f5e639646a7c1 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 18 May 2025 16:47:25 +0800 Subject: [PATCH 30/39] =?UTF-8?q?=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/LakalaApiServiceImpl.java | 102 ++++++++++-------- .../impl/LklLedgerReceiverServiceImpl.java | 22 ++-- .../lakala/service/impl/LklTkServiceImpl.java | 26 +++-- .../store/service/ShopMchEntryService.java | 3 +- .../service/impl/ShopMchEntryServiceImpl.java | 13 ++- 5 files changed, 94 insertions(+), 72 deletions(-) diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 6edbdc51..16610002 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -662,7 +662,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { */ @Override public Pair innerApplyLedgerMer(String merCupNo) { - log.debug("商户分账业务开通申请开始"); + log.debug("商户分账业务申请开始"); if (StringUtils.isBlank(merCupNo)) { return Pair.of(false, I18nUtil._("商户号不能为空!")); @@ -676,7 +676,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 判断是否已经申请过? LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo); - if (lklLedgerMember != null) { + if (lklLedgerMember != null && lklLedgerMember.getAudit_status() == 1) { return Pair.of(true, I18nUtil._("商家已经申请过了!")); } @@ -688,20 +688,21 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setVersion("2.0"); req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 req.setOrgCode(orgCode); - req.setMerInnerNo(shopMchEntry.getLkl_mer_inner_no());// 从进件申请返回的商户号 + req.setMerInnerNo(shopMchEntry.getLkl_mer_inner_no());// 从进件申请返回的内部商户号 req.setMerCupNo(shopMchEntry.getLkl_mer_cup_no()); // 从进件申请返回的商户号 req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 - // new BigDecimal(paramsJSON.getStr("splitLowestRatio")) req.setSplitLowestRatio(new BigDecimal(splitLowestRatio)); req.setEleContractNo(shopMchEntry.getLkl_ec_no()); - String fileName = "小发同城分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); + String fileName = "商家分账授权委托书.pdf";//paramsJSON.getStr("splitEntrustFileName"); req.setSplitEntrustFileName(fileName); // TODO 分账结算委托书文件上传到拉卡拉服务器 JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(shopMchEntry.getContract_download_url())); if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - throw new ApiException(I18nUtil._("小发同城分账授权委托书上传失败!")); + log.error("商家分账授权委托书{}上传失败!", shopMchEntry.getContract_download_url()); + // return Pair.of(false, I18nUtil._("商家分账授权委托书上传失败!")); +// throw new ApiException(I18nUtil._("商家分账授权委托书上传失败!")); } String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); @@ -715,38 +716,45 @@ public class LakalaApiServiceImpl implements LakalaApiService { String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerNotify"; req.setRetUrl(retUrl); - JSONObject paramsJSON = new JSONObject(); - paramsJSON.put("orderNo", req.getOrderNo()); - paramsJSON.put("org_code", orgCode); - paramsJSON.put("version", "2.0"); - paramsJSON.put("ret_url", retUrl); - paramsJSON.put("mer_inner_no", req.getMerInnerNo()); - paramsJSON.put("mer_cup_no", req.getMerCupNo()); - paramsJSON.put("contact_mobile", shopMchEntry.getLogin_mobile()); - paramsJSON.put("split_lowest_ratio", req.getSplitLowestRatio()); - paramsJSON.put("split_range", "MARK"); - paramsJSON.put("split_launch_mode", "MANUAL"); - paramsJSON.put("settle_type", "01"); - paramsJSON.put("split_rule_source", "TR"); - paramsJSON.put("ele_contract_no", ""); - paramsJSON.put("split_entrust_file_name", req.getSplitEntrustFileName()); - paramsJSON.put("split_entrust_file_path", splitEntrustFilePath); + log.debug("商户分账业务申请请求参数:{}", JSONUtil.toJsonStr(req)); + try { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); - - // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} - JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { + if (StrUtil.isBlank(responseStr)) { return Pair.of(false, I18nUtil._("无返回值,申请开通分账失败!")); } - if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { + // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} + JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); + if (lakalaRespJSON == null) { + return Pair.of(false, I18nUtil._("无返回值,申请开通分账失败!")); + } + String applyId = lakalaRespJSON.getStr("applyId"); + + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode) || StrUtil.isBlank(applyId)) { return Pair.of(false, lakalaRespJSON.getStr("retMsg")); } - paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); + JSONObject paramsJSON = new JSONObject(); + paramsJSON.put("orderNo", req.getOrderNo()); + paramsJSON.put("org_code", orgCode); + paramsJSON.put("version", "2.0"); + paramsJSON.put("ret_url", retUrl); + paramsJSON.put("mer_inner_no", req.getMerInnerNo()); + paramsJSON.put("mer_cup_no", shopMchEntry.getLkl_mer_cup_no()); + paramsJSON.put("contact_mobile", shopMchEntry.getLogin_mobile()); + paramsJSON.put("split_lowest_ratio", req.getSplitLowestRatio()); + paramsJSON.put("split_range", "MARK"); + paramsJSON.put("split_launch_mode", "MANUAL"); + paramsJSON.put("settle_type", "01"); + paramsJSON.put("split_rule_source", "TR"); + paramsJSON.put("ele_contract_no", req.getEleContractNo()); + paramsJSON.put("split_entrust_file_name", req.getSplitEntrustFileName()); + paramsJSON.put("split_entrust_file_path", splitEntrustFilePath); + + paramsJSON.set("apply_id", applyId); paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); paramsJSON.set("audit_status_text", paramsJSON.get("remark")); paramsJSON.set("mch_id", shopMchEntry.getId()); @@ -754,9 +762,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 新增数据 // 将 JSON 对象的键名转换为下划线命名 LklLedgerMember lklLedgerMemberNew = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMember.class); - lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMemberNew); + if (!lklLedgerMemberService.saveOrUpdateByMerCupNo(lklLedgerMemberNew)) { + return Pair.of(false, I18nUtil._("商户分账业务材料新增失败,待审核中!")); + } - return Pair.of(true, I18nUtil._("提交成功,待审核中!")); + return Pair.of(true, I18nUtil._("商户分账业务申请提交成功,待审核中!")); } catch (SDKException e) { log.error("申请开通分账出错:", e); return Pair.of(false, I18nUtil._("商家申请开通分账出错!")); @@ -786,7 +796,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { log.error(errMsg + "验签失败"); - return JSONUtil.createObj().set("code", "OP90002").set("retMsg", "验签失败!"); + return JSONUtil.createObj().set("code", "FAIL").set("retMsg", "验签失败!"); } JSONObject paramsJSON = JSONUtil.parseObj(requestBody); @@ -847,13 +857,15 @@ public class LakalaApiServiceImpl implements LakalaApiService { Pair resultPair = lklTkService.registrationMerchant(lklLedgerEc.getMch_mobile(), ""); if (!resultPair.getFirst()) { errMsg += resultPair.getSecond(); -// log.error(errMsg); + log.error(errMsg); shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); -// respData.put("message", errMsg); + // respData.put("message", errMsg); + // return respData; throw new ApiException(errMsg); -// return respData; } + shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_LKL_PADDING, errMsg); + respData.put("code", "SUCCESS"); respData.put("message", "操作成功!"); log.info("商户入网电子合同申请回调:处理成功"); @@ -1171,13 +1183,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setReceiverName(paramsJSON.getStr("receiverName")); req.setContactMobile(mchMobile); - req.setLicenseNo(paramsJSON.getStr("licenseNo")); req.setLicenseName(paramsJSON.getStr("licenseName")); req.setLegalPersonName(paramsJSON.getStr("legalPersonName")); req.setLegalPersonCertificateType(paramsJSON.getStr("legalPersonCertificateType")); req.setLegalPersonCertificateNo(paramsJSON.getStr("legalPersonCertificateNo")); - req.setAcctNo(paramsJSON.getStr("acctNo")); req.setAcctName(paramsJSON.getStr("acctName")); req.setAcctTypeCode(paramsJSON.getStr("acctTypeCode")); @@ -1222,11 +1232,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { - throw new ApiException(I18nUtil._("创建分账接收方无响应!")); + return CommonResult.failed(I18nUtil._("创建分账接收方无响应!")); +// throw new ApiException(I18nUtil._("创建分账接收方无响应!")); } + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + return CommonResult.failed(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); + // throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); } paramsJSON.set("receiver_no", lakalaRespJSON.getByPath("respData.receiverNo")); @@ -1240,17 +1253,14 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 新增或修改本地数据 Boolean success = lklLedgerReceiverService.saveOrUpdateByReceiverNo(lklLedgerReceiver); if (!success) { - log.error("接收方创建成功,但更新本地数据 lklLedgerReceiverService.saveOrUpdateByReceiverNo 失败!"); + log.error("接收方创建成功,但更新本地数据失败!"); + return CommonResult.failed(I18nUtil._("接收方创建成功,但更新本地数据失败!")); } - // 更新商家的has_receiver状态=1 - lklLedgerMemberService.updateMulStatus("", mchMobile, 0, 0, 1, 0); - - return CommonResult.success(lklLedgerReceiver, "创建接收方成功!"); - } catch (SDKException e) { - log.error("接收方创建失败:", e); - throw new ApiException(I18nUtil._("创建接收方失败!"), e); + } catch (Exception e) { + log.error("接收方创建失败:{}", e); + throw new ApiException(I18nUtil._("创建接收方失败:{}"), e); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index d25d9868..d18f39f1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -194,7 +194,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl 0; + boolean success = successCnt > 0; + if (success) { + // 更新多个状态 + lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 0, 1, 0); + } + + return success; } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 4414aea6..f303e458 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -18,7 +18,6 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.api.ResultCode; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.domain.UserDto; -import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.modules.store.ShopMchEntry; import com.suisung.mall.common.utils.RestTemplateHttpUtil; import com.suisung.mall.common.utils.StringUtils; @@ -574,6 +573,8 @@ public class LklTkServiceImpl { return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误"); } + // RMK 拉卡拉进价提交成功,边处理周边的数据,边等待审核异步通知 + // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 @@ -583,10 +584,10 @@ public class LklTkServiceImpl { return new JSONObject().put("code", "FAIL").put("message", "内部商户号:" + merInnerNo + " 入驻信息不存在"); } - Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, data); + Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, null, data); if (!success) { -// return new JSONObject().set("code", "FAIL").set("message", "更新商户号失败"); - throw new ApiException("更新商户号失败"); + return new JSONObject().set("code", "FAIL").set("message", "更新商户号失败"); +// throw new ApiException("更新商户号失败"); } // 备注:RMK 采用拉卡拉的入网电子合同签署流程,暂停e签宝的电子合同生成流程 @@ -608,27 +609,30 @@ public class LklTkServiceImpl { // 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略 // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 - Pair retPair = lakalaApiService.innerApplyLedgerMer(shopMchEntry.getLkl_mer_cup_no()); + Pair retPair = lakalaApiService.innerApplyLedgerMer(merCupNo); if (!retPair.getFirst()) { String message = "商家申请分账功能失败:" + retPair.getSecond(); logger.error(message); - throw new ApiException(message); + return new JSONObject().set("code", "FAIL").set("message", message); +// throw new ApiException(message); } - // 更新商家的hasEsigned状态=1 -// lklLedgerMemberService.updateMulStatus("", shopMchEntry.getLogin_mobile(), 1, 0, 0, 0); - // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); if (!genSuccess) { logger.error("申请分账接收方失败"); - throw new ApiException("申请分账接收方失败"); + return new JSONObject().set("code", "FAIL").set("message", "申请分账接收方失败"); +// throw new ApiException("申请分账接收方失败"); } + // 更新商家的hasEsigned状态=1 +// lklLedgerMemberService.updateMulStatus("", shopMchEntry.getLogin_mobile(), 1, 0, 0, 0); + return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); } - throw new ApiException("进件回调处理失败"); + return new JSONObject().set("code", "FAIL").set("message", "进件回调处理失败"); +// throw new ApiException("进件回调处理失败"); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 16c64804..800bfe32 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -163,10 +163,11 @@ public interface ShopMchEntryService { * @param lklMerCupNo 拉卡拉银联商户号 * @param lklInnerMerNo 拉卡拉内部商户号 * @param lklAuditStatus 拉卡拉审核状态 + * @param approvalStatus 审批状态 * @param lklTkRegResp 进件返回的数据 * @return */ - Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, String lklTkRegResp); + Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegResp); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 9458464f..17a0a73f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -807,21 +807,24 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("lkl_mer_inner_no", lklInnerMerNo); + + if (StrUtil.isNotBlank(lklMerCupNo)) { + updateWrapper.set("lkl_mer_cup_no", lklMerCupNo); + } + if (ObjectUtil.isNotEmpty(lklAuditStatus)) { updateWrapper.set("lkl_tk_audit_status", lklAuditStatus); } - // 商家入驻审核正式通过 - updateWrapper.set("approval_status", CommonConstant.MCH_APPR_STA_PASS); - if (StrUtil.isNotBlank(lklMerCupNo)) { - updateWrapper.set("lkl_mer_cup_no", lklMerCupNo); + if (ObjectUtil.isNotEmpty(approvalStatus)) { + updateWrapper.set("approval_status", approvalStatus); } if (StrUtil.isNotBlank(lklTkRegNotifyReq)) { From a01c9adb254bc411fb391b53d37e3fc55d0a0a93 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Sun, 18 May 2025 23:49:10 +0800 Subject: [PATCH 31/39] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E8=B4=A6?= =?UTF-8?q?=E6=8C=87=E4=BB=A4=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=92=8C=E8=A1=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/lakala/LklOrderSeparate.java | 90 ++++++++++++++++++ .../common/modules/store/ShopMchEntry.java | 4 +- .../lakala/mapper/LklOrderSeparateMapper.java | 19 ++++ .../shop/lakala/service/LakalaApiService.java | 31 ++++-- .../service/impl/LakalaApiServiceImpl.java | 95 ++++++++++++++++++- .../lakala/service/impl/LklTkServiceImpl.java | 25 ++--- .../store/service/ShopMchEntryService.java | 15 +-- .../service/impl/ShopMchEntryServiceImpl.java | 19 ++-- .../impl/ShopStoreBaseServiceImpl.java | 4 + .../mapper/lakala/LklOrderSeparateMapper.xml | 8 ++ 10 files changed, 276 insertions(+), 34 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java create mode 100644 mall-shop/src/main/resources/mapper/lakala/LklOrderSeparateMapper.xml diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java new file mode 100644 index 00000000..d0562013 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.lakala; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("lkl_order_separate") +@ApiModel(value = "拉卡拉分账接收方", description = "拉卡拉分账接收方表") +public class LklOrderSeparate { + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增Id", example = "1") + private Long id; + + @ApiModelProperty(value = "拉卡拉外部商户号") + private String merchant_no; + + @ApiModelProperty(value = "拉卡拉对账单流水号 posp流水号,查清结算用") + private String log_no; + + @ApiModelProperty(value = "交易日期,yyyyMMdd,查清结算用") + private String log_date; + + @ApiModelProperty(value = "商户分账指令流水号,每个商户号下唯一,否则会校验失败") + private String out_separate_no; + + @ApiModelProperty(value = "分账指令流水号,分账系统生成唯一流水") + private String separate_no; + + @ApiModelProperty(value = "分账总金额,单位:分") + private String total_amt; + + @ApiModelProperty(value = "分账计算类型:0- 按照指定金额,1- 按照指定比例。默认 0") + private String cal_type; + + @ApiModelProperty(value = "指令类型 SEPARATE-分账, CANCEL-分账撤销,FALLBACK-分账回退") + private String cmd_type; + + @ApiModelProperty(value = "分账接收类型:0-全部分账到商户本身。1-分账到多方,默认 1") + private String separate_type; + + @ApiModelProperty(value = "分账日期 yyyyMMdd") + private String separate_date; + + @ApiModelProperty(value = "完成日期 yyyyMMdd") + private String finish_date; + + @ApiModelProperty(value = "拉卡拉异步通知回调地址") + private String notify_url; + + @ApiModelProperty(value = "分账接收数据对象,JSON 格式") + private String recv_datas; + + @ApiModelProperty(value = "最终分账明细,JSON 格式") + private String detail_datas; + + @ApiModelProperty(value = "拉卡拉机构编号") + private String lkl_org_no; + + @ApiModelProperty(value = "分账状态:PROCESSING-处理中, ACCEPTED-已受理, SUCCESS-成功, FAIL-失败") + private String status; + + @ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功") + private String final_status; + + @ApiModelProperty(value = "新建时间") + private Date created_at; + + @ApiModelProperty(value = "更新时间") + private Date updated_at; +} \ No newline at end of file diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 831bcedc..87a1645d 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -81,7 +81,6 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "邮箱") private String email; - @ApiModelProperty(value = "店铺地区编号,省份code/城市code/区code") private String store_district; @@ -211,6 +210,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉银联商户号(唯一)") private String lkl_mer_cup_no; + @ApiModelProperty(value = "拉卡拉分配的业务终端号") + private String lkl_term_no; + @ApiModelProperty(value = "拉卡拉审核状态:1-已通过;2-未通过") private Integer lkl_tk_audit_status; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java new file mode 100644 index 00000000..0cc63266 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/mapper/LklOrderSeparateMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.lakala.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.lakala.LklOrderSeparate; +import org.springframework.stereotype.Repository; + + +@Repository +public interface LklOrderSeparateMapper extends BaseMapper { + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index 0e1fea84..e7339007 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -9,6 +9,7 @@ package com.suisung.mall.shop.lakala.service; import cn.hutool.json.JSONObject; +import com.lkl.laop.sdk.request.V3SacsSeparateRequest; import com.suisung.mall.common.api.CommonResult; import org.springframework.data.util.Pair; @@ -181,13 +182,31 @@ public interface LakalaApiService { */ JSONObject getBankCardBin(String bankCardNo); + /** - * @param imgURL - * @param imgType 法人身份证正面图:FR_ID_CARD_FRONT;法人身份证反面:FR_ID_CARD_BEHIND; - * 身份证正面:ID_CARD_FRONT;身份证反面:ID_CARD_BEHIND; - * 营业执照:BUSINESS_LICENSE;银行卡:BANK_CARD + * 查询拉卡拉商户可分账的金额 + * 参考:https://o.lakala.com/#/home/document/detail?id=394 + * + * @param merchantNo 拉卡拉外部商户号 + * @param logNo 拉卡拉对账单流水号 + * @param logDate 拉卡拉对账单交易日期 yyyyMMdd + * @return 响应结果 { + * "merchant_no": "82229005943096D", + * "total_separate_amt": "9900", + * "can_separate_amt": "0", + * "log_date": "20221220", + * "log_no": "66210306990190" + * } + */ + JSONObject queryMchCanSplitAmt(String merchantNo, String logNo, String logDate); + + /** + * 拉卡拉订单分账,用户下单成功之后,进行分账 + * 说明:分账指令是异步处理模式,响应报文成功时,指令状态是”status”: “PROCESSING”,需要等待分账结果通知,或者主动发起查询,建议主动发起查询与分账指令动作之间间隔15秒以上。 + * 参考:https://o.lakala.com/#/home/document/detail?id=389 + * + * @param v3SacsSeparateRequest * @return */ - - + Pair innerDoOrderSeparate(V3SacsSeparateRequest v3SacsSeparateRequest); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 16610002..627de726 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -62,6 +62,7 @@ import java.util.List; public class LakalaApiServiceImpl implements LakalaApiService { private static final boolean init = false; private static final String lklSuccessCode = "000000"; + private static final String lklSacsSuccessCode = "SACS0000"; // 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 @Value("${lakala.merchant_no}") public String merchantNo; // 拉卡拉分配的商户号 @@ -1165,7 +1166,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 判断分账接收方记录是否存在,存在就不再新建了 LklLedgerReceiver lklLedgerReceiverOld = lklLedgerReceiverService.getByCondition(paramsJSON.getStr("licenseNo"), paramsJSON.getStr("contactMobile"), paramsJSON.getLong("platformId")); if (lklLedgerReceiverOld != null) { - return CommonResult.success(lklLedgerReceiverOld, "分账接收方已创建过!"); + return CommonResult.success(lklLedgerReceiverOld, "该接收方已创建过!"); } // 1. 配置初始化 @@ -1232,7 +1233,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String responseStr = LKLSDK.httpPost(req); JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); if (StrUtil.isBlank(responseStr) || lakalaRespJSON == null) { - return CommonResult.failed(I18nUtil._("创建分账接收方无响应!")); + return CommonResult.failed(I18nUtil._("创建分账接收方响应数据无效!")); // throw new ApiException(I18nUtil._("创建分账接收方无响应!")); } @@ -1609,5 +1610,95 @@ public class LakalaApiServiceImpl implements LakalaApiService { return null; } + /** + * 查询拉卡拉商户可分账的金额 + * 参考:https://o.lakala.com/#/home/document/detail?id=394 + * + * @param merchantNo 拉卡拉外部商户号 + * @param logNo 拉卡拉对账单流水号 + * @param logDate 拉卡拉对账单交易日期 yyyyMMdd + * @return 响应结果 { + * "merchant_no": "82229005943096D", + * "total_separate_amt": "9900", + * "can_separate_amt": "0", + * "log_date": "20221220", + * "log_no": "66210306990190" + * } + */ + @Override + public JSONObject queryMchCanSplitAmt(String merchantNo, String logNo, String logDate) { + if (StrUtil.isBlank(merchantNo) || (StrUtil.isBlank(logNo) && StrUtil.isBlank(logDate))) { + return null; + } + + // 1. 配置初始化 + initLKLSDK(); + + //2. 装配数据 + V3SacsQueryAmtRequest req = new V3SacsQueryAmtRequest(); + req.setMerchantNo(merchantNo); + req.setLogNo(logNo); + req.setLogDate(logDate); + + try { + //3. 发送请求 + String responseStr = LKLSDK.httpPost(req); + if (StrUtil.isBlank(responseStr)) { + log.error(I18nUtil._("服务器无返回值!")); + return null; + } + + JSONObject lklRespJSON = JSONUtil.parseObj(responseStr); + if (lklRespJSON == null || !lklSacsSuccessCode.equals(lklRespJSON.getStr("code")) || lklRespJSON.get("resp_data") == null) { + log.error(I18nUtil._("返回值有误!")); + return null; + } + + return (JSONObject) lklRespJSON.get("resp_data"); + } catch (SDKException e) { + log.error("账户余额查询失败:", e); + return null; + } + } + + /** + * 拉卡拉订单分账,用户下单成功之后,进行分账 + * 说明:分账指令是异步处理模式,响应报文成功时,指令状态是”status”: “PROCESSING”,需要等待分账结果通知,或者主动发起查询,建议主动发起查询与分账指令动作之间间隔15秒以上。 + * 参考:https://o.lakala.com/#/home/document/detail?id=389 + * + * @param v3SacsSeparateRequest + * @return + */ + @Override + public Pair innerDoOrderSeparate(V3SacsSeparateRequest v3SacsSeparateRequest) { + if (v3SacsSeparateRequest == null) { + return Pair.of(false, "分账参数不能为空"); + } + + // 1. 配置初始化 + initLKLSDK(); + + try { + log.debug("分账执行请求参数:{}", JSONUtil.toJsonStr(v3SacsSeparateRequest)); + + //3. 发送请求 + String responseStr = LKLSDK.httpPost(v3SacsSeparateRequest); + if (StrUtil.isBlank(responseStr)) { + return Pair.of(false, "服务器无返回值!"); + } + + JSONObject lklRespJSON = JSONUtil.parseObj(responseStr); + if (lklRespJSON == null || !lklSacsSuccessCode.equals(lklRespJSON.getStr("code")) || lklRespJSON.get("resp_data") == null) { + log.error("返回值有误!"); + return Pair.of(false, "返回值有误!"); + } + + return Pair.of(true, "分账成功执行,处理中"); + } catch (SDKException e) { + log.error("账户余额查询失败:", e); + return Pair.of(false, "分账发生错误"); + } + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index f303e458..ddc879ea 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -578,13 +578,18 @@ public class LklTkServiceImpl { // 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据 String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号 String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号 + String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号 + if (StrUtil.isBlank(merInnerNo) || StrUtil.isBlank(merCupNo)) { + return new JSONObject().set("code", "FAIL").set("message", "返回数据有误"); + } + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo); if (ObjectUtil.isEmpty(shopMchEntry)) { logger.error("拉卡拉进件异步通知:返回的内部商户号:{} 入驻信息不存在!", merInnerNo); return new JSONObject().put("code", "FAIL").put("message", "内部商户号:" + merInnerNo + " 入驻信息不存在"); } - Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, CommonConstant.Enable, null, data); + Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data); if (!success) { return new JSONObject().set("code", "FAIL").set("message", "更新商户号失败"); // throw new ApiException("更新商户号失败"); @@ -610,29 +615,27 @@ public class LklTkServiceImpl { // 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略 // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 Pair retPair = lakalaApiService.innerApplyLedgerMer(merCupNo); + + // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 + Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); + + if (retPair.getFirst() && genSuccess) { + return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); + } + if (!retPair.getFirst()) { String message = "商家申请分账功能失败:" + retPair.getSecond(); logger.error(message); return new JSONObject().set("code", "FAIL").set("message", message); -// throw new ApiException(message); } - // 2:新增一个接收方记录,起码要一个平台方,代理商根据入驻信息新增 - Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); if (!genSuccess) { logger.error("申请分账接收方失败"); return new JSONObject().set("code", "FAIL").set("message", "申请分账接收方失败"); -// throw new ApiException("申请分账接收方失败"); } - - // 更新商家的hasEsigned状态=1 -// lklLedgerMemberService.updateMulStatus("", shopMchEntry.getLogin_mobile(), 1, 0, 0, 0); - - return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); } return new JSONObject().set("code", "FAIL").set("message", "进件回调处理失败"); -// throw new ApiException("进件回调处理失败"); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 800bfe32..e170a2dd 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -158,16 +158,17 @@ public interface ShopMchEntryService { Boolean updateMerchEntryLklMerCupNo(String loginMobile, Integer lklAuditStatus, String lklMerCupNo, String lklMerInnerNo, String lklTkRegParams, String lklTkRegResp); /** - * 更新商家入驻申请的拉卡拉审核状态和响应数据 + * 根据拉卡拉内部商户号更新商家入驻申请的拉卡拉审核状态和响应数据 * - * @param lklMerCupNo 拉卡拉银联商户号 - * @param lklInnerMerNo 拉卡拉内部商户号 - * @param lklAuditStatus 拉卡拉审核状态 - * @param approvalStatus 审批状态 - * @param lklTkRegResp 进件返回的数据 + * @param lklInnerMerNo 拉卡拉内部商户号 + * @param lklMerCupNo 拉卡拉外部商户号 + * @param termNos 拉卡拉分配的业务终端号 + * @param lklAuditStatus 拉卡拉审核状态 + * @param approvalStatus 入驻材料审核状态 + * @param lklTkRegNotifyReq lklTkRegResp 异步请求参数 * @return */ - Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegResp); + Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, String termNos, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegNotifyReq); /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 17a0a73f..548fda62 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -800,14 +800,16 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl + + + + + * + + From 9d287da1566bfc44febee1daace2ab20b916917f Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 20 May 2025 17:04:47 +0800 Subject: [PATCH 32/39] =?UTF-8?q?=E5=88=86=E8=B4=A6=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E5=92=8C=E5=BC=82=E6=AD=A5=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E6=96=B9=E6=B3=95=20=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/constant/CommonConstant.java | 3 +- .../common/modules/lakala/LklLedgerEc.java | 1 + .../common/modules/store/ShopMchEntry.java | 15 + .../suisung/mall/common/utils/UploadUtil.java | 15 + .../impl/EsignContractServiceImpl.java | 2 +- .../controller/mobile/LakalaController.java | 29 +- .../shop/lakala/service/LakalaApiService.java | 2 +- .../service/impl/LakalaApiServiceImpl.java | 570 +++++++++++------- .../LklLedgerMerReceiverBindServiceImpl.java | 34 +- .../impl/LklLedgerReceiverServiceImpl.java | 4 +- .../lakala/service/impl/LklTkServiceImpl.java | 50 +- .../store/service/ShopMchEntryService.java | 20 +- .../service/impl/ShopMchEntryServiceImpl.java | 170 ++++-- 13 files changed, 629 insertions(+), 286 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java index 4d84e506..657a063a 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java +++ b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java @@ -45,12 +45,13 @@ public class CommonConstant { public static final Integer PRODUCT_DATA_SOURCE_USER = 1; public static final Integer PRODUCT_DATA_SOURCE_SX = 2; - // 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核; + // 入驻审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核;21-拉卡拉审核未通过; public static final Integer MCH_APPR_STA_PASS = 1; public static final Integer MCH_APPR_STA_NOPASS = 2; public static final Integer MCH_APPR_STA_PADDING = 3; public static final Integer MCH_APPR_STA_NONE = 4; public static final Integer MCH_APPR_STA_LKL_PADDING = 5; + public static final Integer MCH_APPR_STA_LKL_NOPASS = 21; // 入驻商家主体类型,企业或个人:1-企业;2-个人; public static final Integer MCH_ENTITY_TYPE_QY = 1; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java index d87557ea..e03f8862 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerEc.java @@ -39,6 +39,7 @@ public class LklLedgerEc implements Serializable { private String ec_no; private String ec_name; private String ec_file; + private String lkl_file_path; private String ec_status; private Long ec_apply_id; private String result_url; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java index 87a1645d..0131dff4 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/store/ShopMchEntry.java @@ -231,6 +231,9 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "拉卡拉入网电子合同名称") private String lkl_ec_name; + @ApiModelProperty(value = "入网电子合同拉卡拉相对路径") + private String lkl_ec_file_path; + @ApiModelProperty(value = "拉卡拉入网电子合同签署H5地址(进件必须使用)") private String lkl_ec_result_url; @@ -240,6 +243,18 @@ public class ShopMchEntry implements Serializable { @ApiModelProperty(value = "店铺创建状态:1-已启用(入驻已审批,合同已生成);2-未启用") private Integer store_status; + @ApiModelProperty(value = "是否签署电子合同:1-是;2-否;") + private Integer has_ec_signed; + + @ApiModelProperty(value = "是否申请分账业务:1-是;2-否;") + private Integer has_apply_split; + + @ApiModelProperty(value = "是否新增分账接收方:1-是;2-否;") + private Integer has_apply_receiver; + + @ApiModelProperty(value = "是否绑定分账接收方:1-是;2-否;") + private Integer has_bind_receiver; + @ApiModelProperty(value = "该商家入驻记录是否有效,0:无效,1:有效") private Integer status; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java index 1d44950a..5673d391 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/UploadUtil.java @@ -310,6 +310,21 @@ public class UploadUtil { return null; } + public static String fileToBase64(File file) { + if (file == null) { + return null; + } + + try { + byte[] bytes = Files.readAllBytes(file.toPath()); + return Base64Utils.encodeToString(bytes); + } catch (IOException e) { + // 可以在这里添加日志记录,方便调试,这里简单打印异常信息 + log.error("处理file时出现 IOException: ", e.getMessage()); + } + return null; + } + /** * 将MultipartFile 图片转换为Base64字符串 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index fa81915a..a9981128 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -316,7 +316,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl(new JSONObject().put("code", 200).put("msg", "success").toString(), HttpStatus.OK); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java index 71e68954..bb67ced0 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/mobile/LakalaController.java @@ -14,6 +14,8 @@ import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.shop.lakala.service.LakalaApiService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.util.Base64Utils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -52,8 +54,13 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "商户入网电子合同申请回调通知", notes = "商户入网电子合同申请回调通知") @RequestMapping(value = "/ec/applyNotify", method = RequestMethod.POST) - public JSONObject ecApplyNotify(HttpServletRequest request) { - return lakalaPayService.applyLedgerMerEcNotify(request); + public ResponseEntity ecApplyNotify(HttpServletRequest request) { + JSONObject resp = lakalaPayService.applyLedgerMerEcNotify(request); + if (resp != null && "SUCCESS".equals(resp.get("code"))) { + return new ResponseEntity<>(resp, HttpStatus.OK); + } + + return new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR); } @ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请") @@ -64,8 +71,13 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "商户分账业务开通申请异步回调通知", notes = "商户分账业务开通申请异步回调通知") @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) - public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) { - return lakalaPayService.applyLedgerMerNotify(request); + public ResponseEntity ledgerApplyLedgerMerNotify(HttpServletRequest request) { + JSONObject resp = lakalaPayService.applyLedgerMerNotify(request); + if (resp != null && "SUCCESS".equals(resp.get("code"))) { + return new ResponseEntity<>(resp, HttpStatus.OK); + } + + return new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR); } @ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请") @@ -83,7 +95,12 @@ public class LakalaController extends BaseControllerImpl { // https://mall.gpxscs.cn/api/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") @RequestMapping(value = "/ledger/applyLedgerMerReceiverBindNotify", method = RequestMethod.POST) - public JSONObject applyBindNotify(HttpServletRequest request) { - return lakalaPayService.applyLedgerMerReceiverBindNotify(request); + public ResponseEntity applyBindNotify(HttpServletRequest request) { + JSONObject resp = lakalaPayService.applyLedgerMerReceiverBindNotify(request); + if (resp != null && "SUCCESS".equals(resp.get("code"))) { + return new ResponseEntity<>(resp, HttpStatus.OK); + } + + return new ResponseEntity<>(resp, HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java index e7339007..602c77a3 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LakalaApiService.java @@ -133,7 +133,7 @@ public interface LakalaApiService { * @param ecApplyId * @return */ - String LedgerMerEcDownload(Long ecApplyId); + Pair ledgerMerEcDownload(Long ecApplyId); /** * 商户分账业务开通申请回调 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 627de726..96d66b24 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -689,8 +689,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setVersion("2.0"); req.setOrderNo(StringUtils.genLklOrderNo(8));// 14位年月日时(24小时制)分秒+8位的随机数 req.setOrgCode(orgCode); - req.setMerInnerNo(shopMchEntry.getLkl_mer_inner_no());// 从进件申请返回的内部商户号 - req.setMerCupNo(shopMchEntry.getLkl_mer_cup_no()); // 从进件申请返回的商户号 +// req.setMerInnerNo(shopMchEntry.getLkl_mer_inner_no());// 从进件申请返回的内部商户号 + req.setMerCupNo(shopMchEntry.getLkl_mer_cup_no()); // 从进件申请返回的商户号(不要传入内部商户号,传银联商户号才有效) req.setContactMobile(shopMchEntry.getLogin_mobile()); // 商户入驻注册的手机号 // 分账比例为了考虑低价订单的运费占比高,分账比例暂时定70%分账给商户,30%分账给平台 req.setSplitLowestRatio(new BigDecimal(splitLowestRatio)); @@ -699,15 +699,15 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setSplitEntrustFileName(fileName); // TODO 分账结算委托书文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(shopMchEntry.getContract_download_url())); - if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - log.error("商家分账授权委托书{}上传失败!", shopMchEntry.getContract_download_url()); - // return Pair.of(false, I18nUtil._("商家分账授权委托书上传失败!")); -// throw new ApiException(I18nUtil._("商家分账授权委托书上传失败!")); - } +// JSONObject fileUploadResp = uploadFile(req.getOrderNo(), "SPLIT_ENTRUST_FILE", StringUtils.getFileExt(fileName), UploadUtil.fileUrlToBase64(shopMchEntry.getContract_download_url())); +// if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { +// log.error("商家分账授权委托书{}上传失败!", shopMchEntry.getContract_download_url()); +// // return Pair.of(false, I18nUtil._("商家分账授权委托书上传失败!")); +//// throw new ApiException(I18nUtil._("商家分账授权委托书上传失败!")); +// } - String splitEntrustFilePath = fileUploadResp.getStr("attFileId"); - req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf; + String splitEntrustFilePath = shopMchEntry.getLkl_ec_file_path(); //fileUploadResp.getStr("attFileId"); + req.setSplitEntrustFilePath(splitEntrustFilePath); //比如:MMS/20250519/165150-39c8bbca513b4cccab1e942999021fd6.pdf; String domain = projectDomain; if (isProdProject()) { @@ -719,7 +719,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.debug("商户分账业务申请请求参数:{}", JSONUtil.toJsonStr(req)); - try { //3. 发送请求 String responseStr = LKLSDK.httpPost(req); @@ -727,14 +726,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(false, I18nUtil._("无返回值,申请开通分账失败!")); } + log.debug("商户分账业务申请响应数据:{}", responseStr); + // 成功返回示例:{'retCode':'000000','retMsg':'申请已受理,请等待审核结果','respData':{'version':'1.0','orderNo':'KFPT20230223181025407788734','orgCode':'1','applyId':681201215598657536}} JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); if (lakalaRespJSON == null) { return Pair.of(false, I18nUtil._("无返回值,申请开通分账失败!")); } - String applyId = lakalaRespJSON.getStr("applyId"); - if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode) || StrUtil.isBlank(applyId)) { + Object applyId = lakalaRespJSON.getByPath("respData.applyId"); + if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode) || applyId == null) { return Pair.of(false, lakalaRespJSON.getStr("retMsg")); } @@ -743,7 +744,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { paramsJSON.put("org_code", orgCode); paramsJSON.put("version", "2.0"); paramsJSON.put("ret_url", retUrl); - paramsJSON.put("mer_inner_no", req.getMerInnerNo()); + paramsJSON.put("mer_inner_no", shopMchEntry.getLkl_mer_inner_no()); paramsJSON.put("mer_cup_no", shopMchEntry.getLkl_mer_cup_no()); paramsJSON.put("contact_mobile", shopMchEntry.getLogin_mobile()); paramsJSON.put("split_lowest_ratio", req.getSplitLowestRatio()); @@ -790,8 +791,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 验签 String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); - log.debug("商户入网电子合同申请回调返回request body参数:{}", requestBody); - log.debug("商户入网电子合同申请回调返回authorization参数:{}", authorization); + log.debug("商户入网电子合同申请回调返回requestbody 参数:{}\n authorization参数:{}\n", requestBody, authorization); + String errMsg = "商户入网电子合同申请回调:"; boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); @@ -812,7 +813,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { String ecStatus = paramsJSON.getStr("ecStatus"); // COMPLETED if (ecStatus == null || !ecStatus.equals("COMPLETED")) { log.debug("商户入网电子合同申请状态尚未签署完成!"); - respData.put("message", "入网电子合同尚未签署,请稍候!"); + respData.put("message", "商户入网电子合同尚未签署,请稍候!"); return respData; } @@ -838,20 +839,27 @@ public class LakalaApiServiceImpl implements LakalaApiService { } // 把 base64 合同文件,上传到 cos 服务器,返回 url 地址 - String ecFileUrl = LedgerMerEcDownload(ecApplyId); + Pair ecFilePair = ledgerMerEcDownload(ecApplyId); + String ecCosFileUrl = ""; + String eclklFilePath = ""; + if (ecFilePair != null) { + ecCosFileUrl = ecFilePair.getFirst(); + eclklFilePath = ecFilePair.getSecond(); + } // 更改本地记录状态数据 LklLedgerEc updRecord = new LklLedgerEc(); updRecord.setEc_apply_id(ecApplyId); updRecord.setEc_no(ecNo); updRecord.setEc_name(paramsJSON.getStr("ecName")); - updRecord.setEc_file(ecFileUrl); // 合同本地文件COS URL链接 + updRecord.setEc_file(ecCosFileUrl); // 合同本地文件COS URL链接 + updRecord.setLkl_file_path(eclklFilePath); updRecord.setEc_status(paramsJSON.getStr("ecStatus")); // 更新本地数据状态和合同编号、合同名字 Boolean success = lklLedgerEcService.updateByApplyId(updRecord); if (success) { // 更新商家入驻表的合同编号,和签署地址,更改状态 - shopMchEntryService.updateMerchEntryLklEcNo(lklLedgerEc.getMch_id(), ecNo, paramsJSON.getStr("ecName"), lklLedgerEc.getResult_url(), ecFileUrl); + shopMchEntryService.updateMerchEntryLklEcNo(lklLedgerEc.getMch_id(), ecNo, paramsJSON.getStr("ecName"), lklLedgerEc.getResult_url(), ecCosFileUrl, eclklFilePath); // TODO 商家电子合同签署完毕后,收到异步通知,触发拉卡拉商家进件(重要环节) // 下一步,等待拉卡拉系统审核,和人工审核,收到异步通知之后,触发1、e签宝的电子合同签署,2、新增分账接收方 @@ -878,16 +886,16 @@ public class LakalaApiServiceImpl implements LakalaApiService { } /** - * 商户入网盖章电子合同下载 + * 商户入网盖章电子合同下载, 并上传到 cos 服务器 * * @param ecApplyId - * @return + * @return cosUrl, lklFilePath */ @Override - public String LedgerMerEcDownload(Long ecApplyId) { + public Pair ledgerMerEcDownload(Long ecApplyId) { log.debug("商家开始申请入网电子合同"); if (ObjectUtil.isEmpty(ecApplyId)) { - return ""; + return null; } JSONObject reqData = new JSONObject(); @@ -914,32 +922,32 @@ public class LakalaApiServiceImpl implements LakalaApiService { ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { log.error("下载电子合同失败:返回状态有误!"); - return ""; + return null; } JSONObject respBody = response.getBody(); if (ObjectUtil.isNotEmpty(respBody) && !lklSuccessCode.equals(respBody.getStr("code"))) { String errMsg = StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg"); log.error("下载电子合同失败:{}!", errMsg); - return ""; + return null; } JSONObject respData = respBody.getJSONObject("resp_data"); if (respBody.getJSONObject("resp_data") == null) { log.error("下载电子合同失败:返回数据有误!"); - return ""; + return null; } String ecFile = respData.getStr("ec_file"); if (StrUtil.isBlank(ecFile)) { log.error("下载电子合同失败:返回数据有误!"); - return ""; + return null; } LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); if (lklLedgerEc == null) { log.error("下载电子合同失败:未找到对应的入网电子合同记录"); - return ""; + return null; } String fileBase64 = respData.getStr("ec_file"); @@ -956,10 +964,22 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 上传到cos服务器 String cosFileUrl = ossService.uploadObject4OSS(file, cosFileName); + + // 文件上传到拉卡拉服务器 + JSONObject fileUploadResp = uploadFile(StringUtils.genLklOrderNo(8), + "SPLIT_COOPERATION_FILE", + "pdf", + UploadUtil.fileToBase64(file)); + if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { + log.error("下载电子合同失败:未找到对应的入网电子合同记录"); + } + + String lklFilePath = fileUploadResp.getStr("attFileId"); + // 删除临时文件 file.delete(); - return cosFileUrl; + return Pair.of(cosFileUrl, lklFilePath); } /** @@ -1065,8 +1085,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { * @return */ @Transactional - @Override - public JSONObject applyLedgerMerNotify(HttpServletRequest request) { +// @Override + public JSONObject applyLedgerMerNotifyTemp(HttpServletRequest request) { log.debug("商户分账申请业务异步回调通知开始"); // 验签 @@ -1141,8 +1161,8 @@ public class LakalaApiServiceImpl implements LakalaApiService { // return respData; } - // 更新商家的hasApplySplit状态=1;has_esigned=1 - lklLedgerMemberService.updateMulStatus(merCupNo, "", 1, 1, 0, 0); + // 更新商家的hasApplySplit状态=1; + shopMchEntryService.updateMulStatus("", merCupNo, 0, 1, 0, 0); respData.put("code", "SUCCESS"); respData.put("message", "操作成功!"); @@ -1154,6 +1174,102 @@ public class LakalaApiServiceImpl implements LakalaApiService { throw new ApiException("商户分账申请业务回调:操作失败!"); } + /** + * 商户分账业务开通申请回调 + * 参考:https://o.lakala.com/#/home/document/detail?id=379 + * + * @param request HTTP请求 + * @return 处理结果JSON + */ + @Transactional + @Override + public JSONObject applyLedgerMerNotify(HttpServletRequest request) { + log.debug("商户分账申请业务异步回调通知开始"); + + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + log.debug("商户分账申请业务异步回调返回requestbody 参数:{}\n authorization参数:{}\n", requestBody, authorization); + + + if (!LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath)) { + log.error("商户分账申请业务回调:验签失败"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "验签失败!"); + } + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); + if (paramsJSON == null) { + log.error("商户分账申请业务回调:请求参数为空"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "请求参数为空"); + } + + String applyId = paramsJSON.getStr("applyId"); + String auditStatus = paramsJSON.getStr("auditStatus"); + String merCupNo = paramsJSON.getStr("merCupNo"); + + if (StrUtil.isBlank(applyId) || StrUtil.isBlank(auditStatus) || StrUtil.isBlank(merCupNo)) { + String errMsg = "商户分账申请业务回调:缺少必要参数(applyId/auditStatus/merCupNo)"; + log.error(errMsg + ":applyId={}, auditStatus={}, merCupNo={}", applyId, auditStatus, merCupNo); + return JSONUtil.createObj().put("code", "FAIL").put("message", errMsg); + } + + if (!auditStatus.equals("1")) { + log.warn("商户分账申请业务回调:审核未通过,状态={}", auditStatus); + return JSONUtil.createObj().put("code", "FAIL").put("message", "商户分账申请被驳回!"); + } + + LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByApplyId(applyId, CommonConstant.Enable); + if (lklLedgerMember != null) { + log.debug("商户分账申请业务回调:已处理成功,applyId={}", applyId); + return JSONUtil.createObj().put("code", "SUCCESS").put("message", "商户分账申请已处理成功!"); + } + + String merInnerNo = paramsJSON.getStr("merInnerNo"); + String entrustFileName = paramsJSON.getStr("entrustFileName"); + String entrustFilePath = paramsJSON.getStr("entrustFilePath"); + String auditStatusText = paramsJSON.getStr("auditStatusText"); + String remark = paramsJSON.getStr("remark"); + + Boolean updateSuccess = lklLedgerMemberService.updateAuditResult( + applyId, merInnerNo, merCupNo, entrustFileName, entrustFilePath, + auditStatus, auditStatusText, remark + ); + + if (!updateSuccess) { + log.error("商户分账申请业务回调:更新审核结果失败,applyId={}", applyId); + return JSONUtil.createObj().put("code", "FAIL").put("message", "更新审核结果失败"); + } + + try { + JSONObject bindParamsJSON = new JSONObject() + .put("merInnerNo", merInnerNo) + .put("merCupNo", merCupNo); + + Pair bindResult = innerApplyLedgerMerReceiverBind(bindParamsJSON); + if (!bindResult.getFirst()) { + String errMsg = "商户分账申请业务回调:预绑定接收方失败 - " + bindResult.getSecond(); + log.error("商户{}预绑定接收方出错:{}", merCupNo, errMsg); + + // 更新商户审批状态 + if (lklLedgerMember != null) { // 防御性判断(理论上此时应为null,但保留安全检查) + shopMchEntryService.updateMerchEntryApprovalByMchId( + lklLedgerMember.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg + ); + } + return JSONUtil.createObj().put("code", "FAIL").put("message", errMsg); + } + } catch (Exception e) { + log.error("商户分账申请业务回调:绑定接收方异常", e); + return JSONUtil.createObj().put("code", "FAIL").put("message", "绑定接收方失败"); + } + + // 更新商家分账申请状态为已申请(hasApplySplit=1) + shopMchEntryService.updateMulStatus("", merCupNo, 0, 1, 0, 0); + + log.debug("商户分账申请业务回调:处理成功,applyId={}", applyId); + return JSONUtil.createObj().put("code", "SUCCESS").put("message", "操作成功!"); + } + /** * 分账接收方创建申请 * 参考:https://o.lakala.com/#/home/document/detail?id=380 @@ -1258,6 +1374,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { return CommonResult.failed(I18nUtil._("接收方创建成功,但更新本地数据失败!")); } + // 更新商户分账多个状态 has_apply_receiver=1 + shopMchEntryService.updateMulStatus(mchMobile, "", 0, 0, 1, 0); + return CommonResult.success(lklLedgerReceiver, "创建接收方成功!"); } catch (Exception e) { log.error("接收方创建失败:{}", e); @@ -1269,131 +1388,63 @@ public class LakalaApiServiceImpl implements LakalaApiService { * 商家与平台、代理商分账关系绑定申请 * 参考:https://o.lakala.com/#/home/document/detail?id=386 * - * @param paramsJSON + * @param paramsJSON {merCupNo} * @return */ @Override public CommonResult applyLedgerMerReceiverBind(JSONObject paramsJSON) { - // 检查分账方和接收方记录是否存在 - if (lklLedgerMemberService.getByMerCupNo(paramsJSON.getStr("merCupNo")) == null - || lklLedgerReceiverService.getByReceiverNo(paramsJSON.getStr("receiverNo")) == null) { - return CommonResult.failed(I18nUtil._("绑定方不存在!")); + Pair retPair = innerApplyLedgerMerReceiverBind(paramsJSON); + if (!retPair.getFirst()) { + return CommonResult.failed(retPair.getSecond()); } - LklLedgerMerReceiverBind lklLedgerMerReceiverBindOld = lklLedgerMerReceiverBindService.getByCondition(paramsJSON.getStr("merCupNo"), paramsJSON.getStr("receiverNo")); - if (lklLedgerMerReceiverBindOld != null) { - return CommonResult.success(lklLedgerMerReceiverBindOld, "分账绑定关系已存在!"); - } - - // 1. 配置初始化 - initLKLSDK(); - - //2. 装配数据 - V2MmsOpenApiLedgerApplyBindRequest req = new V2MmsOpenApiLedgerApplyBindRequest(); - - String orderNo = StringUtils.genLklOrderNo(8); // 8位随机数 - req.setOrderNo(orderNo); - req.setOrgCode(orgCode); - req.setVersion("2.0"); - - req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); - req.setMerCupNo(paramsJSON.getStr("merCupNo")); - req.setReceiverNo(paramsJSON.getStr("receiverNo")); - - String fileName = paramsJSON.getStr("entrustFileName"); - String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(paramsJSON.getStr("entrustFile")); // 这个是 url 地址,不是 base64 字节码 - req.setEntrustFileName(fileName); - - // 正式上线的时候,调整 api 地址 - String domain = projectDomain; - if (isProdProject()) { - domain += "/api"; - } - // 给拉卡拉通知的回调地址 - String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify"; - req.setRetUrl(retUrl); - - // 文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(orderNo, - "SPLIT_COOPERATION_FILE", - StringUtils.getFileExt(fileName), - splitEntrustFileBase64); - if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - throw new ApiException(I18nUtil._("合作协议上传失败!")); - } - - String entrustFilePath = fileUploadResp.getStr("attFileId"); - req.setEntrustFilePath(entrustFilePath); - - paramsJSON.set("orderNo", orderNo); - paramsJSON.set("version", "2.0"); - paramsJSON.set("ret_url", retUrl); - paramsJSON.set("org_code", orgCode); - paramsJSON.set("entrust_file_name", fileName); - paramsJSON.set("entrust_file_path", entrustFilePath); - - try { - //3. 发送请求 - String responseStr = LKLSDK.httpPost(req); - - JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr); - if (lakalaRespJSON == null) { - throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); - } - - if (!lakalaRespJSON.getStr("retCode").equals(lklSuccessCode)) { - throw new ApiException(I18nUtil._(lakalaRespJSON.getStr("retMsg"))); - } - - paramsJSON.set("apply_id", lakalaRespJSON.getByPath("respData.applyId")); - paramsJSON.set("remark", lakalaRespJSON.getStr("retMsg")); - - // 新增数据 - // 将 JSON 对象的键名转换为下划线命名 - LklLedgerMerReceiverBind lklLedgerMerReceiverBind = JSONUtil.toBean(StringUtils.convertCamelToSnake(paramsJSON.toString()), LklLedgerMerReceiverBind.class); - lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(lklLedgerMerReceiverBind); - - return CommonResult.success(lklLedgerMerReceiverBind, "提交成功,待审核中!"); - } catch (SDKException e) { - log.error("分账绑定关系申请失败:", e); - throw new ApiException(I18nUtil._("分账绑定关系申请失败!"), e); - } + return CommonResult.success(null, "接收方绑定成功!"); } /** - * 内部调用分账关系绑定申请 + * 内部调用分账关系绑定申请(废弃) * 参考:https://o.lakala.com/#/home/document/detail?id=386 * * @param paramsJSON * @return */ - public Pair innerApplyLedgerMerReceiverBind(JSONObject paramsJSON) { - // 检查分账方和接收方记录是否存在 - if (lklLedgerMemberService.getByMerCupNo(paramsJSON.getStr("merCupNo")) == null) { - return Pair.of(false, I18nUtil._("绑定方不存在!")); + public Pair innerApplyLedgerMerReceiverBindTemp(JSONObject paramsJSON) { + if (paramsJSON == null) { + return Pair.of(false, I18nUtil._("绑定参数有误!")); + } + + String merCupNo = paramsJSON.getStr("merCupNo"); + if (StrUtil.isBlank(merCupNo)) { + return Pair.of(false, I18nUtil._("商户参数不能为空!")); } // 获取商家入驻记录 - ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(paramsJSON.getStr("merCupNo")); + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); if (shopMchEntry == null) { return Pair.of(false, I18nUtil._("商户入驻记录不存在!")); } + // 检查分账方和接收方记录是否存在 + LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo); + if (lklLedgerMember == null) { + return Pair.of(false, I18nUtil._("商家尚未做分账业务申请!")); + } + // 代理商Id,平台默认为0 - Long platformId = shopMchEntry.getDistributor_id(); +// Long platformId = shopMchEntry.getDistributor_id(); String entrustFileName = "小发同城合作协议书.pdf"; - String entrustFileUrl = shopMchEntry.getContract_download_url(); +// String entrustFileUrl = shopMchEntry.getContract_download_url(); int successCnt = 0; // 获取平台接收方记录(可能多个记录,平台+代理商) List lklLedgerReceiverList = lklLedgerReceiverService.getByCondition("", shopMchEntry.getLogin_mobile()); if (CollectionUtils.isEmpty(lklLedgerReceiverList)) { - return Pair.of(false, I18nUtil._("分账接收方不存在!")); + return Pair.of(false, I18nUtil._("先新增接收方信息!")); } for (LklLedgerReceiver lklLedgerReceiver : lklLedgerReceiverList) { - LklLedgerMerReceiverBind lklLedgerMerReceiverBindOld = lklLedgerMerReceiverBindService.getByCondition(paramsJSON.getStr("merCupNo"), paramsJSON.getStr("receiverNo")); + LklLedgerMerReceiverBind lklLedgerMerReceiverBindOld = lklLedgerMerReceiverBindService.getByCondition(merCupNo, lklLedgerReceiver.getReceiver_no()); if (lklLedgerMerReceiverBindOld != null) { // return Pair.of(false, "分账绑定关系已存在!"); continue; @@ -1410,12 +1461,12 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setOrgCode(orgCode); req.setVersion("2.0"); - req.setMerInnerNo(paramsJSON.getStr("merInnerNo")); - req.setMerCupNo(paramsJSON.getStr("merCupNo")); + req.setMerInnerNo(lklLedgerMember.getMer_inner_no()); + req.setMerCupNo(merCupNo); req.setReceiverNo(lklLedgerReceiver.getReceiver_no()); // String fileName = paramsJSON.getStr("entrustFileName"); - String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(entrustFileUrl); // 这个是 url 地址,不是 base64 字节码 + //String splitEntrustFileBase64 = UploadUtil.fileUrlToBase64(entrustFileUrl); // 这个是 url 地址,不是 base64 字节码 req.setEntrustFileName(entrustFileName); String domain = projectDomain; @@ -1427,27 +1478,30 @@ public class LakalaApiServiceImpl implements LakalaApiService { req.setRetUrl(retUrl); // 文件上传到拉卡拉服务器 - JSONObject fileUploadResp = uploadFile(orderNo, - "SPLIT_COOPERATION_FILE", - StringUtils.getFileExt(entrustFileName), - splitEntrustFileBase64); - if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { - // throw new ApiException(I18nUtil._("合作协议上传失败!")); - log.error(I18nUtil._("合作协议上传失败!")); - continue; - } +// JSONObject fileUploadResp = uploadFile(orderNo, +// "SPLIT_COOPERATION_FILE", +// StringUtils.getFileExt(entrustFileName), +// splitEntrustFileBase64); +// if (fileUploadResp == null || StrUtil.isBlank(fileUploadResp.getStr("attFileId"))) { +// // throw new ApiException(I18nUtil._("合作协议上传失败!")); +// log.error(I18nUtil._("合作协议上传失败!")); +// continue; +// } - String entrustFilePath = fileUploadResp.getStr("attFileId"); + String entrustFilePath = shopMchEntry.getLkl_ec_file_path();//fileUploadResp.getStr("attFileId"); req.setEntrustFilePath(entrustFilePath); paramsJSON.set("orderNo", orderNo); paramsJSON.set("version", "2.0"); paramsJSON.set("ret_url", retUrl); paramsJSON.set("org_code", orgCode); + paramsJSON.set("merInnerNo", lklLedgerMember.getMer_inner_no()); paramsJSON.set("entrust_file_name", entrustFileName); paramsJSON.set("entrust_file_path", entrustFilePath); try { + log.debug("绑定接收方参数:{}", JSONUtil.toJsonStr(req)); + //3. 发送请求 String responseStr = LKLSDK.httpPost(req); @@ -1483,93 +1537,191 @@ public class LakalaApiServiceImpl implements LakalaApiService { return Pair.of(true, "提交成功,待审核中!"); } + /** + * 内部调用分账关系绑定申请(优化版) + * 参考:https://o.lakala.com/#/home/document/detail?id=386 + * + * @param paramsJSON 包含绑定参数的JSON对象 {merCupNo} + * @return 操作结果及提示信息 + */ + public Pair innerApplyLedgerMerReceiverBind(JSONObject paramsJSON) { + // 1. 参数校验(提前失败) + if (paramsJSON == null) { + return Pair.of(false, I18nUtil._("绑定参数为空")); + } + + String merCupNo = paramsJSON.getStr("merCupNo"); + if (StrUtil.isBlank(merCupNo)) { + return Pair.of(false, I18nUtil._("商户号(merCupNo)为空")); + } + + // 2. 基础数据查询(提前失败) + ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); + if (shopMchEntry == null) { + return Pair.of(false, I18nUtil._("商户入驻记录不存在")); + } + + LklLedgerMember lklLedgerMember = lklLedgerMemberService.getByMerCupNo(merCupNo); + if (lklLedgerMember == null) { + return Pair.of(false, I18nUtil._("商家尚未做分账业务申请")); + } + + List receiverList = lklLedgerReceiverService.getByCondition("", shopMchEntry.getLogin_mobile()); + if (CollectionUtils.isEmpty(receiverList)) { + return Pair.of(false, I18nUtil._("接收方信息为空")); + } + + // 3. 公共参数准备(避免循环内重复计算) + String domain = projectDomain; + if (isProdProject()) { + domain += "/api"; + } + String retUrl = domain + "/mobile/shop/lakala/ledger/applyLedgerMerReceiverBindNotify"; + String entrustFileName = "小发同城合作协议书.pdf"; + String entrustFilePath = shopMchEntry.getLkl_ec_file_path(); + + int successCount = 0; + int totalCount = receiverList.size(); + + // 5. 初始化SDK(建议移至类初始化或统一配置) + initLKLSDK(); + + // 4. 循环处理接收方绑定 + for (LklLedgerReceiver receiver : receiverList) { + try { + // 跳过已存在的绑定关系 + if (lklLedgerMerReceiverBindService.getByCondition(merCupNo, receiver.getReceiver_no()) != null) { + log.warn("分账绑定关系已存在:merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no()); + continue; + } + + // 6. 构建请求参数 + String orderNo = StringUtils.genLklOrderNo(8); + V2MmsOpenApiLedgerApplyBindRequest request = new V2MmsOpenApiLedgerApplyBindRequest(); + request.setOrderNo(orderNo); + request.setOrgCode(orgCode); + request.setVersion("2.0"); + request.setMerInnerNo(lklLedgerMember.getMer_inner_no()); + request.setMerCupNo(merCupNo); + request.setReceiverNo(receiver.getReceiver_no()); + request.setEntrustFileName(entrustFileName); + request.setEntrustFilePath(entrustFilePath); + request.setRetUrl(retUrl); + + // 7. 记录请求参数 + log.debug("绑定接收方参数:{}", JSONUtil.toJsonStr(request)); + + // 8. 发送请求并处理响应 + String responseStr = LKLSDK.httpPost(request); + JSONObject respJson = JSONUtil.parseObj(responseStr); + + if (respJson == null || !lklSuccessCode.equals(respJson.getStr("retCode"))) { + log.error("拉卡拉响应失败:{}", respJson != null ? respJson.getStr("retMsg") : "无响应数据"); + continue; // 单个失败不影响其他接收方处理 + } + + // 9. 更新参数并保存记录 + paramsJSON.set("orderNo", orderNo); + paramsJSON.set("apply_id", respJson.getByPath("respData.applyId")); + paramsJSON.set("receiver_no", receiver.getReceiver_no()); + paramsJSON.set("remark", respJson.getStr("retMsg")); + + // 转换JSON键名格式并保存 + String snakeJson = StringUtils.convertCamelToSnake(paramsJSON.toString()); + LklLedgerMerReceiverBind bindRecord = JSONUtil.toBean(snakeJson, LklLedgerMerReceiverBind.class); + + if (lklLedgerMerReceiverBindService.saveOrUpdateByMerCupNoReceiverNo(bindRecord)) { + successCount++; + } else { + log.warn("绑定记录保存失败:merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no()); + } + + } catch (Exception e) { + log.error("处理分账绑定失败:merCupNo={}, receiverNo={}", merCupNo, receiver.getReceiver_no(), e); + // 单个接收方处理失败,继续处理其他接收方 + } + } + + // 10. 返回结果 + if (successCount == 0) { + return Pair.of(false, "所有分账绑定均失败"); + } else if (successCount < totalCount) { + return Pair.of(true, "部分提交成功(" + successCount + "/" + totalCount + "),待审核中"); + } else { + return Pair.of(true, "全部提交成功,待审核中"); + } + } + /** * 分账关系绑定申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 * - * @param request - * @return + * @param request HTTP请求对象 + * @return 处理结果JSON */ @Transactional @Override public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { log.debug("分账商家绑定接收方异步回调通知开始"); - // 验签 + + // 1. 验签处理(提前失败返回) String authorization = request.getHeader("Authorization"); String requestBody = LakalaUtil.getBody(request); - log.debug("分账商家绑定接收方异步回调返回request body参数:{}", requestBody); - log.debug("分账商家绑定接收方异步回调返回authorization参数:{}", authorization); + log.debug("回调参数:requestBody={}\nauthorization={}", requestBody, authorization); - boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); - if (!checkSuccess) { - return JSONUtil.createObj().put("code", "FAIL").put("message", "验签失败!"); + if (!LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath)) { + log.error("验签失败,拒绝处理回调"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "验签失败"); } + // 2. 参数解析与校验 JSONObject paramsJSON = JSONUtil.parseObj(requestBody); - JSONObject respData = new JSONObject(); - respData.put("code", "FAIL"); - respData.put("message", "处理失败!"); - - if (paramsJSON != null) { - String merCupNo = paramsJSON.getStr("merCupNo"); - String applyId = paramsJSON.getStr("applyId"); - String auditStatus = paramsJSON.getStr("auditStatus"); - if (StrUtil.isBlank(merCupNo) || StrUtil.isBlank(applyId) || StrUtil.isBlank(auditStatus)) { - String errMsg = "缺少返回必要参数"; - log.error(errMsg + ":applyId={}, applyId={}, auditStatus={}", merCupNo, applyId, auditStatus); - - respData.put("message", errMsg); - return respData; - } - - //auditStatus:1:通过,2拒绝 - if (!auditStatus.equals("1")) { - respData.put("message", "绑定接收方被驳回!"); - return respData; - } - - Boolean success = lklLedgerMerReceiverBindService.updateAuditResult(applyId, - paramsJSON.getStr("merInnerNo"), - merCupNo, - paramsJSON.getStr("receiverNo"), - paramsJSON.getStr("entrustFileName"), - paramsJSON.getStr("entrustFilePath"), - paramsJSON.getStr("auditStatus"), - paramsJSON.getStr("auditStatusText"), - paramsJSON.getStr("remark")); - if (success) { - // 更改商家的状态 has_bind_receiver 状态=1 - lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 0, 0, 1); - - // TODO 新建一个正式的已审核通过的店铺, 新建之前判断是否已经新建过了? - // 新建一个正式的已审核通过的店铺 - ShopMchEntry shopEntry = shopMchEntryService.getShopMerchEntryByMerCupNo(merCupNo); - if (shopEntry != null && !CommonConstant.Enable.equals(shopEntry.getStore_status())) { - String mchMobile = shopEntry.getLogin_mobile(); - Pair retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(mchMobile); - if (retPair.getFirst() > 0) { - // 2025-05-17暂停e签宝电子合同生成流程 - // 更改合同记录表的店铺id - // esignContractService.updateContractStoreId(mchMobile, retPair.getFirst()); - // 填充合同模版表的店铺Id - // esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); - // 店铺创建状态已完成 - shopMchEntryService.updateMerchEntryStoreStatus(mchMobile, CommonConstant.Enable); - } else { - throw new ApiException("商家绑定接收方:创建初始化店铺失败!"); - } - } - - respData.put("code", "SUCCESS"); - respData.put("message", "操作成功!"); - return respData; - } + if (paramsJSON == null || !paramsJSON.containsKey("respData")) { + log.error("回调参数缺失respData字段"); + return JSONUtil.createObj().put("code", "FAIL").put("message", "参数格式错误"); } - throw new ApiException("商家绑定接收方:操作失败!"); + JSONObject respData = paramsJSON.getJSONObject("respData"); + String merCupNo = respData.getStr("merCupNo"); + String applyId = respData.getStr("applyId"); + String auditStatus = respData.getStr("auditStatus"); -// throw new ServiceException("分账绑定关系申请回调失败!"); -// return respData; + // 3. 核心参数校验 + if (org.apache.commons.lang3.StringUtils.isAnyBlank(merCupNo, applyId, auditStatus)) { + String errorMsg = "关键参数缺失:merCupNo={}, applyId={}, auditStatus={}"; + log.error(errorMsg, merCupNo, applyId, auditStatus); + return JSONUtil.createObj().put("code", "FAIL").put("message", "接收方绑定参数有误"); + } + + // 4. 审核状态判断 + if (!"1".equals(auditStatus)) { + log.warn("绑定审核未通过,状态:{}", auditStatus); + return JSONUtil.createObj().put("code", "FAIL").put("message", "绑定接收方被驳回"); + } + + // 5. 更新绑定记录状态 + Boolean updateSuccess = lklLedgerMerReceiverBindService.updateAuditResult( + applyId, + respData.getStr("merInnerNo"), + merCupNo, + respData.getStr("receiverNo"), + respData.getStr("entrustFileName"), + respData.getStr("entrustFilePath"), + auditStatus, + respData.getStr("auditStatusText"), + respData.getStr("remark") + ); + + if (!updateSuccess) { + log.error("更新绑定记录失败,applyId:{}", applyId); + return JSONUtil.createObj().put("code", "FAIL").put("message", "更新绑定状态失败"); + } + + // 6. 更新商家绑定状态 + shopMchEntryService.updateMulStatus("", merCupNo, 0, 0, 0, 1); + + log.debug("分账商家绑定接收方回调处理完成,merCupNo:{}", merCupNo); + return JSONUtil.createObj().put("code", "SUCCESS").put("message", "操作成功"); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java index 0c38a474..004d2064 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMerReceiverBindServiceImpl.java @@ -87,15 +87,31 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("apply_id", applyId); - updateWrapper.set("receiver_no", receiverNo); - updateWrapper.set("mer_inner_no", merInnerNo); - updateWrapper.set("mer_cup_no", merCupNo); - updateWrapper.set("entrust_file_name", entrustFileName); - updateWrapper.set("entrust_file_path", entrustFilePath); - updateWrapper.set("audit_status", auditStatus); - updateWrapper.set("audit_status_text", auditStatusText); - updateWrapper.set("remark", remark); - + if (StrUtil.isNotBlank(merInnerNo)) { + updateWrapper.set("mer_inner_no", merInnerNo); + } + if (StrUtil.isNotBlank(merCupNo)) { + updateWrapper.set("mer_cup_no", merCupNo); + } + if (StrUtil.isNotBlank(receiverNo)) { + updateWrapper.set("receiver_no", receiverNo); + } + if (StrUtil.isNotBlank(entrustFileName)) { + updateWrapper.set("entrust_file_name", entrustFileName); + } + if (StrUtil.isNotBlank(entrustFilePath)) { + updateWrapper.set("entrust_file_path", entrustFilePath); + } + if (StrUtil.isNotBlank(auditStatus)) { + updateWrapper.set("audit_status", auditStatus); + } + if (StrUtil.isNotBlank(auditStatusText)) { + updateWrapper.set("audit_status_text", auditStatusText); + } + if (StrUtil.isNotBlank(remark)) { + updateWrapper.set("remark", remark); + } + return update(updateWrapper); } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index d18f39f1..6e259c24 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -15,6 +15,7 @@ import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.api.ResultCode; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.esign.EsignPlatformInfo; import com.suisung.mall.common.modules.lakala.LklLedgerReceiver; @@ -209,6 +210,7 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl retPair = shopStoreBaseService.merchEntryInfo2StoreInfo(mchMobile); +// if (retPair.getFirst() > 0) { +// // 2025-05-17暂停e签宝电子合同生成流程 +// // 更改合同记录表的店铺id +// // esignContractService.updateContractStoreId(mchMobile, retPair.getFirst()); +// // 填充合同模版表的店铺Id +// // esignContractFillingFileService.updateContractFillingStoreId(mchMobile, retPair.getFirst()); +// // 店铺创建状态已完成 +// shopMchEntryService.updateMerchEntryStoreStatus(mchMobile, CommonConstant.Enable); +// } else { +// throw new ApiException("商家进件:初始化店铺失败!"); +// } +// } + // 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略 // 下一步等待拉卡拉审核通过,再绑定接收方和商家的关系 Pair retPair = lakalaApiService.innerApplyLedgerMer(merCupNo); @@ -620,22 +644,22 @@ public class LklTkServiceImpl { Boolean genSuccess = lklLedgerReceiverService.innerApplyLedgerReceiver(merCupNo, shopMchEntry.getDistributor_id()); if (retPair.getFirst() && genSuccess) { - return new JSONObject().put("code", "SUCCESS").put("message", "处理成功"); + return new JSONObject().put("code", "200").put("message", "处理成功"); } if (!retPair.getFirst()) { String message = "商家申请分账功能失败:" + retPair.getSecond(); logger.error(message); - return new JSONObject().set("code", "FAIL").set("message", message); + return new JSONObject().set("code", "500").set("message", message); } if (!genSuccess) { logger.error("申请分账接收方失败"); - return new JSONObject().set("code", "FAIL").set("message", "申请分账接收方失败"); + return new JSONObject().set("code", "500").set("message", "申请分账接收方失败"); } } - return new JSONObject().set("code", "FAIL").set("message", "进件回调处理失败"); + return new JSONObject().set("code", "500").set("message", "进件回调处理失败"); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index e170a2dd..08932b76 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -168,7 +168,7 @@ public interface ShopMchEntryService { * @param lklTkRegNotifyReq lklTkRegResp 异步请求参数 * @return */ - Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklMerCupNo, String lklInnerMerNo, String termNos, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegNotifyReq); + Boolean updateMerchEntryLklAuditStatusByLklMerCupNo(String lklInnerMerNo, String lklMerCupNo, String termNos, Integer lklAuditStatus, Integer approvalStatus, String lklTkRegNotifyReq); /** @@ -181,16 +181,17 @@ public interface ShopMchEntryService { Boolean updateMerchEntryStoreId(Long id, Integer storeId); /** - * 更新拉卡拉入网电子合同、合同名称、签署地址 + * 更新拉卡拉入网电子合同、合同名称、签署COS地址, LKL文件相对路径 * * @param id * @param lklEcNo * @param lklEcName * @param lklEcResultUrl * @param ecDownloadUrl + * @param ecLklFilePath * @return */ - Boolean updateMerchEntryLklEcNo(Long id, String lklEcNo, String lklEcName, String lklEcResultUrl, String ecDownloadUrl); + Boolean updateMerchEntryLklEcNo(Long id, String lklEcNo, String lklEcName, String lklEcResultUrl, String ecDownloadUrl, String ecLklFilePath); /** * 更新商家入驻申请的审批状态和审批备注 @@ -203,4 +204,17 @@ public interface ShopMchEntryService { */ Boolean updateMerchEntryApprovalByMchId(Long mchId, String mchMobile, Integer approvalStatus, String approvalRemark); + /** + * 根据商户号或商家手机号修改商户分账多个状态 + * + * @param mchMobile + * @param merCupNo + * @param hasEcSigned + * @param hasApplySplit + * @param hasApplyReceiver + * @param hasBindReceiver + * @return + */ + Boolean updateMulStatus(String mchMobile, String merCupNo, Integer hasEcSigned, Integer hasApplySplit, Integer hasApplyReceiver, Integer hasBindReceiver); + } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 548fda62..3639e6bf 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -113,7 +113,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); + // 设置查询条件 + Optional.ofNullable(mchMobile) + .filter(StrUtil::isNotBlank) + .ifPresent(mobile -> updateWrapper.eq("login_mobile", mobile)); + Optional.ofNullable(merCupNo) + .filter(StrUtil::isNotBlank) + .ifPresent(cupNo -> updateWrapper.eq("lkl_mer_cup_no", cupNo)); + + // 流式构建更新字段 + Map fieldMap = new LinkedHashMap<>(); + fieldMap.put("has_ec_signed", hasEcSigned); + fieldMap.put("has_apply_split", hasApplySplit); + fieldMap.put("has_apply_receiver", hasApplyReceiver); + fieldMap.put("has_bind_receiver", hasBindReceiver); + + // 过滤有效字段并设置 + fieldMap.entrySet().stream() + .filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .forEach(entry -> updateWrapper.set(entry.getKey(), entry.getValue())); + + + try { + return update(updateWrapper); + } catch (Exception e) { + log.error("更新商家分账业务多个状态失败", e); + return false; + } + } } From bff10a587ef44d38da28d2bd07e9172e34aeadaf Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Tue, 20 May 2025 18:10:37 +0800 Subject: [PATCH 33/39] =?UTF-8?q?im=E9=A1=B9=E7=9B=AE=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=95=BF=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websocket/service/onchat/MallsuiteImSocketHandler.java | 4 +++- mall-im/src/main/java/com/suisung/mall/im/pojo/vo/SendVO.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mall-im/src/main/java/com/suisung/mall/im/common/websocket/service/onchat/MallsuiteImSocketHandler.java b/mall-im/src/main/java/com/suisung/mall/im/common/websocket/service/onchat/MallsuiteImSocketHandler.java index b106263b..3e552707 100644 --- a/mall-im/src/main/java/com/suisung/mall/im/common/websocket/service/onchat/MallsuiteImSocketHandler.java +++ b/mall-im/src/main/java/com/suisung/mall/im/common/websocket/service/onchat/MallsuiteImSocketHandler.java @@ -205,7 +205,9 @@ public class MallsuiteImSocketHandler implements WebSocketHandler { if (!mine.getId().equals(to.getId())) { sendVO.setMine(false); - + if ("voice".equals(receiveDTO.getMine().getType()) || "video".equals(receiveDTO.getMine().getType())) { + sendVO.setMessage_length(receiveDTO.getMine().getContent()); + } //保存聊天记录 if ("friend".equals(type) || "user".equals(type)) { //如果是私聊 diff --git a/mall-im/src/main/java/com/suisung/mall/im/pojo/vo/SendVO.java b/mall-im/src/main/java/com/suisung/mall/im/pojo/vo/SendVO.java index ddf36383..1d71302c 100644 --- a/mall-im/src/main/java/com/suisung/mall/im/pojo/vo/SendVO.java +++ b/mall-im/src/main/java/com/suisung/mall/im/pojo/vo/SendVO.java @@ -76,6 +76,9 @@ public class SendVO implements Serializable { @ApiModelProperty(value = "和状态一致") private Map msg; + @ApiModelProperty(value = "消息长度") + private String message_length; + @Override public String toString() { From 1459581e371b8ef4f910aaa6f81f51fd28d6ae84 Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Tue, 20 May 2025 17:43:02 +0800 Subject: [PATCH 34/39] =?UTF-8?q?=E5=95=86=E7=91=9E9.7=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9C=8D=E5=8A=A1=E7=AB=AF=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suisung/mall/common/enums/DicEnum.java | 88 ++ .../common/modules/sixun/SxSyncGoods.java | 3 +- .../common/modules/sync/StoreDbConfig.java | 87 ++ .../mall/common/modules/sync/SyncFileLog.java | 103 +++ .../mall/common/utils/ContextUtil.java | 24 +- mall-shop/pom.xml | 6 + .../ShopBaseProductCategoryService.java | 6 + .../impl/AccountBaseConfigServiceImpl.java | 1 + .../ShopBaseProductCategoryServiceImpl.java | 23 + .../impl/ShopBaseProductTypeServiceImpl.java | 3 +- .../ShopChainUserRightsBaseServiceImpl.java | 1 - .../mall/shop/config/GlobalCorsConfig.java | 30 + .../suisung/mall/shop/config/WebConfig.java | 12 + .../number/mapper/ShopNumberSeqMapper.java | 5 + .../number/service/ShopNumberSeqService.java | 7 + .../impl/ShopNumberSeqServiceImpl.java | 130 +++ .../mall/shop/page/service/OssService.java | 24 + .../page/service/impl/OssServiceImpl.java | 51 +- .../ShopProductAssistIndexService.java | 4 + .../service/ShopProductBaseService.java | 6 + .../service/ShopProductImageService.java | 5 + .../ShopProductAssistIndexServiceImpl.java | 26 + .../impl/ShopProductBaseServiceImpl.java | 855 +++++++++++++++++- .../impl/ShopProductImageServiceImpl.java | 29 + .../suisung/mall/shop/sixun/dao/BaseDao.java | 148 +++ .../mall/shop/sixun/dao/SxDataDao.java | 238 +++++ .../mall/shop/sixun/dto/DataBaseInfo.java | 16 + .../mall/shop/sixun/dto/ProductImage.java | 17 + .../mall/shop/sixun/dto/PromotionDetail.java | 17 + .../mall/shop/sixun/dto/ResultDto.java | 15 + .../mall/shop/sixun/dto/SxCategoryModel.java | 34 + .../mall/shop/sixun/dto/SxGoosModel.java | 103 +++ .../sixun/service/SxSyncCategoryService.java | 20 + .../sixun/service/SxSyncGoodsService.java | 17 + .../shop/sixun/service/SxSyncVipService.java | 15 + .../impl/SxSyncCategoryServiceImpl.java | 84 +- .../service/impl/SxSyncGoodsServiceImpl.java | 16 +- .../service/impl/SxSyncVipServiceImpl.java | 16 +- .../mall/shop/sixun/utils/FileUtils.java | 65 ++ .../shop/sync/Utils/BatchInsertUtils.java | 91 ++ .../mall/shop/sync/Utils/CryptoUtils.java | 117 +++ .../mall/shop/sync/Utils/ThreadFileUtils.java | 37 + .../sync/controller/ClientController.java | 29 + .../controller/StoreDbConfigController.java | 107 +++ .../controller/SyncThirdDataController.java | 65 +- .../mall/shop/sync/keymanage/RedisKey.java | 6 + .../shop/sync/mapper/StoreDbConfigMapper.java | 18 + .../shop/sync/mapper/SyncFileLogMapper.java | 17 + .../shop/sync/pool/ThreadPoolManager.java | 414 +++++++++ .../sync/service/StoreDbConfigService.java | 33 + .../shop/sync/service/SyncAppService.java | 11 + .../shop/sync/service/SyncFileLogService.java | 23 + .../sync/service/SyncThirdDataService.java | 29 + .../impl/StoreDbConfigServiceImpl.java | 187 ++++ .../sync/service/impl/SyncAppServiceImpl.java | 53 ++ .../service/impl/SyncBaseThirdSxAbstract.java | 695 ++++++++++++++ .../service/impl/SyncConfigServiceImpl.java | 2 + .../service/impl/SyncFileLogServiceImpl.java | 23 + .../impl/SyncThirdDataServiceImpl.java | 797 ++++++++-------- .../src/main/resources/bootstrap-dev.yml | 2 +- .../src/main/resources/bootstrap-local.yml | 7 +- .../src/main/resources/bootstrap-prod.yml | 2 +- .../src/main/resources/bootstrap-test.yml | 2 +- .../src/main/resources/bootstrap-uat.yml | 2 +- .../mapper/number/ShopNumberSeqMapper.xml | 27 + sql/shop/dev/20250520_ddl.sql | 51 ++ 66 files changed, 4790 insertions(+), 407 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/sync/StoreDbConfig.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/sync/SyncFileLog.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/config/GlobalCorsConfig.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/BaseDao.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/SxDataDao.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/DataBaseInfo.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ProductImage.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/PromotionDetail.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ResultDto.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxCategoryModel.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxGoosModel.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sixun/utils/FileUtils.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BatchInsertUtils.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/CryptoUtils.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ThreadFileUtils.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/StoreDbConfigMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/SyncFileLogMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/pool/ThreadPoolManager.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/service/StoreDbConfigService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncFileLogService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncFileLogServiceImpl.java create mode 100644 sql/shop/dev/20250520_ddl.sql diff --git a/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java b/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java new file mode 100644 index 00000000..4629dd01 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java @@ -0,0 +1,88 @@ +package com.suisung.mall.common.enums; + +public enum DicEnum { + + ERR_1003("1003","缺少必要参数","errCode","错误码","缺少必要参数"), + ERR_1001("1001","签名有误","errCode","错误码","签名有误"), + ERR_1004("1004","缺少必要参数","errCode","错误码","缺少必要参数"), + + DATA_SOURCE_1("1","自添加","dtaSource","数据来源","数据来源"), + DATA_SOURCE_2("2","缺少必要参数","dtaSource","数据来源","数据来源"), + + PRODUCT("1", "商品","product","同步类型","同步类型"), + PRODUCT_CATEGORY("2", "商品分类","productCategory","同步类型","数据来源"), + BRAND("3", "品牌","brand","同步类型","同步类型"), + MEMBER("4", "会员","member","同步类型","同步类型"), + + PENDING("0", "等待中","brand","同步类型","同步类型"), + PROCESSING("1", "进行中","brand","同步类型","同步类型"), + SUCCESS("2", "成功","brand","同步类型","同步类型"), + FAILED("3", "失败","brand","同步类型","同步类型"), + + SOURCE_SYSTEM_TYPE_1005("1005", "思迅","sourceSystemType","数据来源","数据来源"), + SOURCE_SYSTEM_TYPE_SELF("self", "蓝驰","sourceSystemType","数据来源","数据来源"), + TIMED("1", "定时同步","syncMode","同步类型","同步类型"), + INTERVAL("2", "间隔同步","syncMode","同步类型","同步类型"), + + YESORNO_0("0", "否","yesOrno","是否","是否"), + YESORNO_1("1", "是","yesOrno","是否","是否"), + ; + ; + private String code; + + private String value; + + private String dicType; + + private String dicName; + + private String desc; + + DicEnum(String code, String value, String dicType, String dicName, String desc) { + this.code = code; + this.value = value; + this.dicType = dicType; + this.dicName = dicName; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getDicType() { + return dicType; + } + + public void setDicType(String dicType) { + this.dicType = dicType; + } + + public String getDicName() { + return dicName; + } + + public void setDicName(String dicName) { + this.dicName = dicName; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/sixun/SxSyncGoods.java b/mall-common/src/main/java/com/suisung/mall/common/modules/sixun/SxSyncGoods.java index a5745389..40209967 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/sixun/SxSyncGoods.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/sixun/SxSyncGoods.java @@ -91,7 +91,7 @@ public class SxSyncGoods implements Serializable { private BigDecimal item_brand_name; @ApiModelProperty(value = "商品助记号") - private Integer item_rem; + private String item_rem; @ApiModelProperty(value = "生产日期") private String build_date; @@ -113,5 +113,6 @@ public class SxSyncGoods implements Serializable { @ApiModelProperty(value = "更新时间") private Date updated_at; + } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/sync/StoreDbConfig.java b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/StoreDbConfig.java new file mode 100644 index 00000000..7c979547 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/StoreDbConfig.java @@ -0,0 +1,87 @@ +package com.suisung.mall.common.modules.sync; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("store_db_config") +@ApiModel(value = "StoreDbConfig对象", description = "店铺数据库连接配置表") +public class StoreDbConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty(value = "主键ID") + private Long id; + + @TableField("store_id") + @ApiModelProperty(value = "店铺ID") + private String storeId; + + @TableField("db_type") + @ApiModelProperty(value = "数据库类型(mysql/oracle/sqlserver等)") + private String dbType = "sqlserver"; + + @TableField("db_name") + @ApiModelProperty(value = "数据库名称") + private String dbName; + + @TableField("db_ip") + @ApiModelProperty(value = "数据库IP地址") + private String dbIp; + + @TableField("db_port") + @ApiModelProperty(value = "数据库端口") + private Integer dbPort = 3306; + + @TableField("db_username") + @ApiModelProperty(value = "数据库用户名") + private String dbUsername; + + @TableField("db_password") + @ApiModelProperty(value = "数据库密码(建议加密存储)") + private String dbPassword; + + @TableField("has_internet") + @ApiModelProperty(value = "是否有外网访问(0:无,1:有)") + private String hasInternet; + + @TableField("sync_mode") + @ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)") + private String syncMode; + + @TableField("has_start") + @ApiModelProperty(value = "是否启用(0:否,1:是)") + private String hasStart; + + @TableField("cron_expression") + @ApiModelProperty(value = "定时同步的cron表达式") + private String cronExpression; + + @TableField("category_name") + @ApiModelProperty(value = "商品分类") + private String categoryName; + + @TableField("create_time") + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @TableField("update_time") + @ApiModelProperty(value = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @TableField("remark") + @ApiModelProperty(value = "备注信息") + private String remark; +} \ No newline at end of file diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/sync/SyncFileLog.java b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/SyncFileLog.java new file mode 100644 index 00000000..f4694574 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/SyncFileLog.java @@ -0,0 +1,103 @@ +package com.suisung.mall.common.modules.sync; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import javax.validation.constraints.NotEmpty; +import java.util.Date; +import java.util.Map; +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@ApiModel(value = "文件同步日志表实体类", description = "文件同步日志表实体类") +@TableName("sync_file_log") +@Data +public class SyncFileLog { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + @ApiModelProperty(value = "自增ID") + private Long id; + + @TableField(value = "sync_task_id") + @ApiModelProperty(value = "同步任务ID") + private String syncTaskId; + + @TableField(value = "sync_store_id") + @ApiModelProperty(value = "店铺id") + private String syncStoreId; + + @TableField(value = "file_path") + @ApiModelProperty(value = "文件路径") + private String filePath; + + @TableField(value = "file_name") + @ApiModelProperty(value = "文件名") + private String fileName; + + @TableField(value = "file_size") + @ApiModelProperty(value = "文件大小(字节)") + private Long fileSize; + + @TableField(value = "file_md5") + @ApiModelProperty(value = "文件MD5值") + private String fileMd5; + + @TableField(value = "source_system") + @ApiModelProperty(value = "源系统标识") + @NotEmpty + private String sourceSystem; + + @TableField(value = "target_system") + @ApiModelProperty(value = "目标系统标识") + @NotEmpty + private String targetSystem; + + @TableField(value = "sync_type") + @ApiModelProperty(value = "同步类型(1:商品,2:商品分类,3:会员,4:品牌)") + private String syncType; + + @TableField(value = "sync_status") + @ApiModelProperty(value = "同步状态(0:等待中,1:进行中,2:成功,3:失败)") + private String syncStatus; + + @TableField(value = "retry_count") + @ApiModelProperty(value = "重试次数") + private Integer retryCount; + + @TableField(value = "error_message") + @ApiModelProperty(value = "错误信息") + private String errorMessage; + + @TableField(value = "start_time") + @ApiModelProperty(value = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date startTime; + + @TableField(value = "end_time") + @ApiModelProperty(value = "结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date endTime; + + @TableField(value = "duration") + @ApiModelProperty(value = "耗时(毫秒)") + private Integer duration; + + @TableField(value = "create_time", fill = FieldFill.DEFAULT) + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @TableField(value = "update_time", fill = FieldFill.DEFAULT) + @ApiModelProperty(value = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @TableField(value = "extra_info", typeHandler = com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler.class) + @ApiModelProperty(value = "额外信息(JSON格式)") + private Map extraInfo; + +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java b/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java index 60ac8005..b5214cff 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/ContextUtil.java @@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; +import java.util.Objects; @Component @Slf4j @@ -39,8 +40,12 @@ public class ContextUtil { public static UserDto getCurrentUser() { try { UserDto loginUser = staticUserInfoService.getUser(); - // log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser)); - return loginUser; + log.info("##### 当前登录用户:{}###", JsonUtil.object2json(loginUser)); + return loginUser;//todo 测试去除 +// UserDto user= new UserDto(); +// user.setStore_id("1"); +// user.setRole_id(9); +// return user; } catch (Exception e) { System.out.println(e.getMessage()); } @@ -73,6 +78,21 @@ public class ContextUtil { return loginUser.getId(); } + /** + * 传入的 + * @param storeId + * @return + */ + public static String getStoreId(String storeId){ + if(getCurrentUser()==null){ + throw new RuntimeException("未登录"); + } + if(Objects.requireNonNull(getCurrentUser()).getRole_id()==9){//平台 + return storeId; + } + return Objects.requireNonNull(getCurrentUser()).getStore_id(); + } + @PostConstruct public void init() { ContextUtil.staticUserInfoService = userInfoService; diff --git a/mall-shop/pom.xml b/mall-shop/pom.xml index 1942428b..49369c3e 100644 --- a/mall-shop/pom.xml +++ b/mall-shop/pom.xml @@ -294,6 +294,12 @@ 2.8.0 compile + + + com.microsoft.sqlserver + mssql-jdbc + 9.2.1.jre8 + diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductCategoryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductCategoryService.java index 880fba4f..b50f1792 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductCategoryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductCategoryService.java @@ -143,4 +143,10 @@ public interface ShopBaseProductCategoryService extends IBaseService configMap = configList.stream() .collect(Collectors.toMap(AccountBaseConfig::getConfig_key, config -> config)); + redisService.hSetAll(RedisConstant.Config_Cache_Key, configMap); redisService.incr(RedisConstant.Config_Cache_Version, 1); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java index d2e941d9..7670f63c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductCategoryServiceImpl.java @@ -26,6 +26,7 @@ import com.suisung.mall.common.modules.product.ShopProductIndex; import com.suisung.mall.common.modules.product.ShopProductItem; import com.suisung.mall.common.modules.sixun.SxSyncCategory; import com.suisung.mall.common.modules.store.ShopStoreActivityItem; +import com.suisung.mall.common.modules.store.ShopStoreProductCategory; import com.suisung.mall.common.modules.user.ShopUserCart; import com.suisung.mall.common.pojo.dto.ProductSearchDTO; import com.suisung.mall.common.utils.CheckUtil; @@ -1235,4 +1236,26 @@ public class ShopBaseProductCategoryServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + List categoryList = find(queryWrapper); + // 类似数据可以放到前端整理 + List category_tmp_rows = Convert.toList(Map.class, categoryList); + map=new HashMap(); + for (Map category_row : category_tmp_rows) { + map.put(category_row.get("category_name"),category_row.get("category_id")); + } + if (CollUtil.isNotEmpty(map)) redisService.set(cache_key, map, 60 * 60); + + } + return map; + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java index db6ae310..bd1ca3d1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java @@ -85,7 +85,8 @@ public class ShopBaseProductTypeServiceImpl extends BaseServiceImpl * Id管理表 Mapper 接口 @@ -16,4 +18,7 @@ import org.springframework.stereotype.Repository; @Repository public interface ShopNumberSeqMapper extends BaseMapper { + List findNumberFromShopBaseAndItem(ShopNumberSeq shopNumberSeq); + List findProductAndImtemId(ShopNumberSeq shopNumberSeq); + void myUpdateSeq(ShopNumberSeq shopNumberSeq); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/ShopNumberSeqService.java b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/ShopNumberSeqService.java index eaa5e852..8d3ca7f6 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/ShopNumberSeqService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/ShopNumberSeqService.java @@ -3,6 +3,8 @@ package com.suisung.mall.shop.number.service; import com.suisung.mall.common.modules.number.ShopNumberSeq; import com.suisung.mall.core.web.service.IBaseService; +import java.util.List; + /** *

* Id管理表 服务类 @@ -17,4 +19,9 @@ public interface ShopNumberSeqService extends IBaseService { Long createNextNo(String prefix); + List batchCreateNextNo(String seqName, int batchSize); + + void clearRelateGoodsId(); + void clearKey(); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java index 1a1df401..7384c498 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java @@ -1,15 +1,25 @@ package com.suisung.mall.shop.number.service.impl; import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.number.ShopNumberSeq; +import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.number.mapper.ShopNumberSeqMapper; import com.suisung.mall.shop.number.service.ShopNumberSeqService; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.LongStream; /** @@ -21,8 +31,15 @@ import java.util.Date; * @since 2021-09-18 */ @Service +@lombok.extern.slf4j.Slf4j public class ShopNumberSeqServiceImpl extends BaseServiceImpl implements ShopNumberSeqService { + @Autowired + private ShopNumberSeqMapper shopNumberSeqMapper; + @Autowired + private RedisService redisService; + private String CACHE_PREFIX = "shop_number_seq:%S"; + /** * 得到下一个Id * 方法走到这里会产生串行化,集群部署这里不能使用单机锁 @@ -65,6 +82,10 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl1; + while (!flag){ + try { + Thread.sleep(3600); + } catch (InterruptedException e) { + log.error("checkPrimaryKey枷锁失败--"+e.getMessage()); + break; + } + flag=shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1; + } + + } + + + /** + * 批量获取id + * @param seqName + * @param batchSize + * @return + */ + @Transactional(propagation = Propagation.NOT_SUPPORTED) + public synchronized List batchCreateNextNo(String seqName, int batchSize) { + if (batchSize <= 0) { + return Collections.emptyList(); + } + long number= 0; + if (null==redisService.get(String.format(CACHE_PREFIX, seqName))) { + // 1. 获取当前序列值 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("prefix", seqName); + ShopNumberSeq seq = getById(seqName); + + if (seq == null) { + seq = new ShopNumberSeq(); + seq.setPrefix(seqName); + seq.setNumber((long) batchSize); + save(seq); + return LongStream.range(1, batchSize + 1).boxed().collect(Collectors.toList()); + } + number = seq.getNumber(); + }else { + int numberCache=(Integer) redisService.get(String.format(CACHE_PREFIX, seqName))+1; + number= numberCache; + + } + + // 2. 计算新值范围 + long start = number; + long end = start + batchSize - 1; + + // 3. 更新序列值到缓存,在并发时使用 + redisService.set(String.format(CACHE_PREFIX, seqName), end); + // 4. 返回生成的ID范围 + return LongStream.rangeClosed(start, end).boxed().collect(Collectors.toList()); + } + + public void batchUpdateSeq(List shopNumberSeqList){ + int count=0; + for (int i = 0; i < shopNumberSeqList.size(); i++) { + shopNumberSeqMapper.myUpdateSeq(shopNumberSeqList.get(i)); + count++; + } + log.info("更新成功{}条数据",count); + } + public void clearKey(){ + redisService.del(String.format(CACHE_PREFIX,"item_id")); + redisService.del(String.format(CACHE_PREFIX,"product_id")); + } + + /** + * 清除缓存,专门给并发使用,防止redis的缓存没有加载 + */ + @Override + public void clearRelateGoodsId(){ + boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1; + if(flag){ + return; + } + List shopNumberSeqList=shopNumberSeqMapper.findProductAndImtemId(new ShopNumberSeq()); + for (ShopNumberSeq shopNumberSeq:shopNumberSeqList) { + if(shopNumberSeq.getPrefix().equals("product_id")){ + clearCache("product_id",shopNumberSeq.getNumber()); + } + if(shopNumberSeq.getPrefix().equals("item_id")){ + clearCache("item_id",shopNumberSeq.getNumber()); + } + } + } + /** + * 刷新缓存 + */ + private void clearCache(String seqName,long number){ + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("prefix", seqName); + ShopNumberSeq seq = getById(seqName); + if (seq != null) { + seq = new ShopNumberSeq(); + seq.setNumber(number-1); + seq.setPrefix(seqName); + } + edit(seq); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/OssService.java b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/OssService.java index 92324c09..4e5c53b8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/OssService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/OssService.java @@ -1,12 +1,14 @@ package com.suisung.mall.shop.page.service; +import com.qcloud.cos.model.COSObjectSummary; import com.suisung.mall.common.pojo.dto.OssCallbackResultDTO; import com.suisung.mall.common.pojo.dto.OssPolicyResultDTO; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.InputStream; +import java.util.List; /** * oss上传管理Service @@ -42,4 +44,26 @@ public interface OssService { */ String uploadObject4OSS(String fileUrl, String concat); + /** + * 根据目录查询目录下的目录列表 + * @param folder + * @return + */ + List listFolders(String folder); + + /** + * 根据目录查询目录下的文件 + * @param folder + * @return + */ + List listDocuments(String folder); + + /** + * 下载文件返回路径 + * @param ossFolder + * @param localFolder + * @return + */ + String download(String ossFolder, String localFolder); + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java index 3199fbde..342b5142 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/page/service/impl/OssServiceImpl.java @@ -14,9 +14,7 @@ import com.qcloud.cos.COSClient; import com.qcloud.cos.ClientConfig; import com.qcloud.cos.auth.BasicCOSCredentials; import com.qcloud.cos.auth.COSCredentials; -import com.qcloud.cos.model.CannedAccessControlList; -import com.qcloud.cos.model.PutObjectRequest; -import com.qcloud.cos.model.PutObjectResult; +import com.qcloud.cos.model.*; import com.qcloud.cos.region.Region; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.constant.ConfigConstant; @@ -49,7 +47,9 @@ import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * oss上传管理Service实现类 @@ -569,4 +569,49 @@ public class OssServiceImpl implements OssService { } } } + + @Override + public List listFolders(String folder) { + COSClient ossCli = initCOSClient(); + ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); + listObjectsRequest.setBucketName(TENGXUN_BUCKET_NAME); + listObjectsRequest.setPrefix(folder); + listObjectsRequest.setDelimiter("/"); + ObjectListing objectListing = ossCli.listObjects(listObjectsRequest); + List commonPrefixes = objectListing.getCommonPrefixes(); + logger.info(JSONUtil.toJsonStr(commonPrefixes)); + return commonPrefixes; + } + + @Override + public List listDocuments(String folder) { + COSClient ossCli = initCOSClient(); + ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); + listObjectsRequest.setBucketName(TENGXUN_BUCKET_NAME); + listObjectsRequest.setPrefix(folder); + listObjectsRequest.setDelimiter(""); + ObjectListing objectListing = ossCli.listObjects(listObjectsRequest); + List files = objectListing.getObjectSummaries() + .stream() + // 过滤掉目录(目录通常以 '/' 结尾或大小为0) + .filter(obj -> !obj.getKey().endsWith("/") || obj.getSize() > 0) + .collect(Collectors.toList()); + // 获取目录下的文件 + return files; + } + + /** + * + * @param ossFolder 如folder/example.txt + * @param localFolder 如/path/to/local/example.txt + * @return + */ + @Override + public String download(String ossFolder, String localFolder) { + COSClient ossCli = initCOSClient(); + ossCli.getObject(new GetObjectRequest(TENGXUN_BUCKET_NAME, ossFolder), + new File(localFolder)); + return localFolder; + } + } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductAssistIndexService.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductAssistIndexService.java index 2a81ed24..9cd955f9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductAssistIndexService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductAssistIndexService.java @@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service; import com.suisung.mall.common.modules.product.ShopProductAssistIndex; import com.suisung.mall.core.web.service.IBaseService; +import java.util.List; + /** *

* 商品与属性对应表 服务类 @@ -12,5 +14,7 @@ import com.suisung.mall.core.web.service.IBaseService; * @since 2021-05-19 */ public interface ShopProductAssistIndexService extends IBaseService { + List getShopProductAssistIndexStoreId(Integer storeId); + void clearCacheShopProductAssistIndexByStoreId(Integer storeId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductBaseService.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductBaseService.java index 7f12ca15..43ba5b21 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductBaseService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductBaseService.java @@ -283,4 +283,10 @@ public interface ShopProductBaseService extends IBaseService { Pair saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List shopProductItemList, List shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List shopProductAssistIndexList); + Pair saveProductBatch(List shopProductBaseList, List shopProductIndexList, + List shopProductDataList, List shopProductDetailList, + List shopProductInfoList, List> shopProductItemList, + List> shopProductImageList, + List shopProductValidPeriodList, + List shopProductAssistIndexList); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductImageService.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductImageService.java index 03dfccef..04f15e22 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductImageService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductImageService.java @@ -3,6 +3,8 @@ package com.suisung.mall.shop.product.service; import com.suisung.mall.common.modules.product.ShopProductImage; import com.suisung.mall.core.web.service.IBaseService; +import java.util.List; + /** *

* 产品图片表,按照颜色规格 服务类 @@ -13,4 +15,7 @@ import com.suisung.mall.core.web.service.IBaseService; */ public interface ShopProductImageService extends IBaseService { + List getShopProductImageByStoreId(Integer storeId); + + void clearCacheShopProductImageByStoreId(Integer storeId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductAssistIndexServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductAssistIndexServiceImpl.java index 28a03fbe..3a108074 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductAssistIndexServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductAssistIndexServiceImpl.java @@ -1,11 +1,17 @@ package com.suisung.mall.shop.product.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.product.ShopProductAssistIndex; +import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.product.mapper.ShopProductAssistIndexMapper; import com.suisung.mall.shop.product.service.ShopProductAssistIndexService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + /** *

@@ -17,4 +23,24 @@ import org.springframework.stereotype.Service; */ @Service public class ShopProductAssistIndexServiceImpl extends BaseServiceImpl implements ShopProductAssistIndexService { + + @Autowired + private RedisService redisService; + + @Override + public List getShopProductAssistIndexStoreId(Integer storeId) { + List shopProductAssistIndexList= (List) redisService.get("ShopProductAssistIndexStoreId:"+storeId); + if(shopProductAssistIndexList==null){ + QueryWrapper queryWrapper= new QueryWrapper(); + queryWrapper.eq("store_id",storeId); + shopProductAssistIndexList=this.list(queryWrapper); + redisService.set("ShopProductAssistIndexStoreId:"+storeId,shopProductAssistIndexList); + } + return shopProductAssistIndexList; + } + + @Override + public void clearCacheShopProductAssistIndexByStoreId(Integer storeId) { + redisService.del("ShopProductAssistIndexStoreId:"+storeId); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java index dcd17f5c..3829658c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java @@ -6,6 +6,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.StopWatch; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; @@ -15,6 +16,8 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.mapper.Mapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.api.CommonResult; @@ -62,14 +65,22 @@ import com.suisung.mall.shop.product.pojo.vo.ProductVo; import com.suisung.mall.shop.product.service.*; import com.suisung.mall.shop.sixun.service.SxSyncGoodsService; import com.suisung.mall.shop.store.service.*; +import com.suisung.mall.shop.sync.Utils.BatchInsertUtils; import com.suisung.mall.shop.user.service.*; import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; +import org.mybatis.spring.SqlSessionFactoryBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionTemplate; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -81,7 +92,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadPoolExecutor; +import java.util.function.Function; import java.util.stream.Collectors; import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser; @@ -195,6 +208,11 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List shopProductItemList, List shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List shopProductAssistIndexList) { + public synchronized Pair saveProduct(ShopProductBase shopProductBase, ShopProductIndex shopProductIndex, ShopProductData shopProductData, ShopProductDetail shopProductDetail, ShopProductInfo shopProductInfo, List shopProductItemList, List shopProductImageList, ShopProductValidPeriod shopProductValidPeriod, List shopProductAssistIndexList) { Integer store_id = shopProductBase.getStore_id(); if (store_id == null) { return Pair.of(false, I18nUtil._("缺少店铺ID!")); @@ -718,7 +736,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl wrapper, Integer pageNum, Integer pageSize) { Map map = new HashMap(); - Integer store_id = Convert.toInt(getCurrentUser().getStore_id()); + Integer store_id = Convert.toInt(getCurrentUser().getStore_id(),1); Integer nodeid = Convert.toInt(getParameter("nodeid"), 0); if (CheckUtil.isNotEmpty(nodeid)) { @@ -5243,4 +5261,835 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl saveProductBatch(List shopProductBaseList, List shopProductIndexList, + List shopProductDataList, List shopProductDetailList, + List shopProductInfoList, List> shopProductItemList, + List> shopProductImageList, List shopProductValidPeriodList, + List shopProductAssistIndexList) { + + // 1. 参数校验 + if (shopProductBaseList == null || shopProductBaseList.isEmpty()) { + return Pair.of(false, "商品列表不能为空"); + } + + // 2. 检查并设置已存在商品的ID + Map existingProducts = checkExistingProducts(shopProductBaseList); + + // 3. 分离新增和更新的商品 + List newProducts = new ArrayList<>(); + List updateProducts = new ArrayList<>(); + + List newShopProductIndexList = new ArrayList<>(); + List updateShopProductIndexList = new ArrayList<>(); + + List newProductDataList=new ArrayList<>(); + List updateProductDataList=new ArrayList<>(); + + List newShopProductDetailList=new ArrayList<>(); + List updateShopProductDetailList=new ArrayList<>(); + + List newShopProductInfoList=new ArrayList<>(); + List updateShopProductInfoList=new ArrayList<>(); + + List> newShopProductItemList=new ArrayList<>(); + List> updateShopProductItemList=new ArrayList<>(); + + List> newShopProductImageList=new ArrayList<>(); + List> updateShopProductImageList=new ArrayList<>(); + + List newShopProductValidPeriodList=new ArrayList<>(); + List updateShopProductValidPeriodList=new ArrayList<>(); + + List newShopProductAssistIndexList=new ArrayList<>(); + List updateShopProductAssistIndexList=new ArrayList<>(); + try { + for (int i = 0; i < shopProductBaseList.size(); i++) { + ShopProductBase base = shopProductBaseList.get(i); + String key = base.getStore_id() + "_" + base.getProduct_number(); + if (existingProducts.containsKey(key)) { + + // 已存在商品,设置ID并加入更新列表 + Long existId = existingProducts.get(key); + base.setProduct_id(existId); + + shopProductBaseList.get(i).setProduct_id(existId); + //shopProductIndexList.get(i).setProduct_id(existId); + // shopProductIndexList.get(i).setProduct_unit_points(BigDecimal.ZERO); + shopProductIndexList.get(i).setProduct_unit_price_max(base.getProduct_market_price()); + shopProductIndexList.get(i).setProduct_unit_sp(Convert.toBigDecimal(base.getProduct_unit_sp())); + shopProductIndexList.get(i).setProduct_sale_time(base.getProduct_sale_time().getTime()); + shopProductIndexList.get(i).setProduct_verify_id(base.getProduct_verify_id()); + shopProductIndexList.get(i).setProduct_state_id(base.getProduct_state_id()); + // 判断店铺是否开启 +// shopProductIndexList.get(i).setStore_is_open(1); +// shopProductIndexList.get(i).setStore_is_selfsupport(1); +// shopProductIndexList.get(i).setStore_type(1); +// shopProductIndexList.get(i).setSubsite_id(0); +// shopProductIndexList.get(i).setProduct_number(base.getProduct_number()); + +// shopProductDataList.get(i).setProduct_id(existId); +// shopProductDetailList.get(i).setProduct_id(existId); +// shopProductInfoList.get(i).setProduct_id(existId); + if(CollUtil.isNotEmpty(shopProductIndexList)){ + updateShopProductIndexList.add(shopProductIndexList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductDataList)){ + updateProductDataList.add(shopProductDataList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductDetailList)){ + updateShopProductDetailList.add(shopProductDetailList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductInfoList)){ + updateShopProductInfoList.add(shopProductInfoList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductItemList)){ + updateShopProductItemList.add(shopProductItemList.get(i)); + } + + if(CollUtil.isNotEmpty(shopProductImageList)){ + updateShopProductImageList.add(shopProductImageList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductValidPeriodList)){ + updateShopProductValidPeriodList.add(shopProductValidPeriodList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductAssistIndexList)){ + updateShopProductAssistIndexList.add(shopProductAssistIndexList.get(i)); + } + + updateProducts.add(base); + + } else { + base.setProduct_verify_id(StateCode.PRODUCT_VERIFY_PASSED);//审核通过 + base.setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF);//下架状态 + + shopProductIndexList.get(i).setProduct_unit_points(BigDecimal.ZERO); + shopProductIndexList.get(i).setProduct_unit_price_max(base.getProduct_market_price()); + shopProductIndexList.get(i).setProduct_unit_sp(Convert.toBigDecimal(base.getProduct_unit_sp())); + shopProductIndexList.get(i).setProduct_sale_time(base.getProduct_sale_time().getTime()); + shopProductIndexList.get(i).setProduct_verify_id(base.getProduct_verify_id()); + shopProductIndexList.get(i).setProduct_state_id(base.getProduct_state_id()); + // 判断店铺是否开启 + shopProductIndexList.get(i).setStore_is_open(1); + shopProductIndexList.get(i).setStore_is_selfsupport(1); + shopProductIndexList.get(i).setStore_type(1); + shopProductIndexList.get(i).setSubsite_id(0); + shopProductIndexList.get(i).setProduct_number(base.getProduct_number()); + + if(CollUtil.isNotEmpty(shopProductIndexList)){ + newShopProductIndexList.add(shopProductIndexList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductDataList)){ + newProductDataList.add(shopProductDataList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductDetailList)){ + newShopProductDetailList.add(shopProductDetailList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductInfoList)){ + newShopProductInfoList.add(shopProductInfoList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductItemList)){ + newShopProductItemList.add(shopProductItemList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductImageList)){ + newShopProductImageList.add(shopProductImageList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductValidPeriodList)){ + newShopProductValidPeriodList.add(shopProductValidPeriodList.get(i)); + } + if(CollUtil.isNotEmpty(shopProductAssistIndexList)){ + newShopProductAssistIndexList.add(shopProductAssistIndexList.get(i)); + } + // 新商品,加入新增列表 + newProducts.add(base); + } + + } + }catch (RuntimeException e){ + logger.info("异常报错:{}",e.getMessage()); + } + + return executeBatchOperations(newProducts,updateProducts,newShopProductIndexList,updateShopProductIndexList, + newProductDataList,updateProductDataList,newShopProductDetailList,updateShopProductDetailList, + newShopProductInfoList,updateShopProductInfoList,newShopProductItemList,updateShopProductItemList, + newShopProductImageList,updateShopProductImageList,newShopProductValidPeriodList,updateShopProductValidPeriodList, + newShopProductAssistIndexList,updateShopProductAssistIndexList); + } + + /** + * 执行批量操作(新增和更新分开处理) + */ + private Pair executeBatchOperations(List newProducts, List updateProducts, + List newShopProductIndexList,List updateShopProductIndexList, + List newShopProductDataList, List updateShopProductDataList, + List newShopProductDetailList, List updateShopProductDetailList, + List newShopProductInfoList, List updateShopProductInfoList, + List> newShopProductItemList,List> udpateShopProductItemList, + List> newShopProductImageList, List> udpteShopProductImageList, + List newShopProductValidPeriodList, List updateShopProductValidPeriodList, + List newShopProductAssistIndexList, List udpateShopProductAssistIndexList + ) { + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); + transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); + transactionTemplate.setTimeout(60); // 60秒超时 + return transactionTemplate.execute(status -> { + try { + // Map> productToItemsMap = new HashMap<>(); + List addAnalyticsList = new ArrayList<>(); + List udpateAnalyticsList = new ArrayList<>(); + + List addItemSeqs = new ArrayList<>(); + List updateItemSeqs = new ArrayList<>(); + + List addItemIds = new ArrayList<>(); + List udpateItemIds = new ArrayList<>(); + List addShopProductItems=new ArrayList<>(); + List updateShopProductItems=new ArrayList<>(); + int taskCount = 2; + CountDownLatch latch = new CountDownLatch(taskCount); + // 1. 批量新增 + if (CollUtil.isNotEmpty(newProducts)) { + // 4. 批量生成新商品的ID + List newIds = shopNumberSeqService.batchCreateNextNo("product_id", newProducts.size()); + if (newIds == null || newIds.size() != newProducts.size()) { + return Pair.of(false, "生成商品编号异常"); + } + for (int i = 0; i < newIds.size(); i++) { + Long productId = newIds.get(i); + ShopProductBase base = newProducts.get(i); + base.setProduct_id(productId); + // 设置关联ID + newProducts.get(i).setProduct_id(productId); + newShopProductIndexList.get(i).setProduct_id(productId); + newShopProductDataList.get(i).setProduct_id(productId); + newShopProductDetailList.get(i).setProduct_id(productId); + newShopProductInfoList.get(i).setProduct_id(productId); + + // 处理商品项 + List items = newShopProductItemList.get(i); + processProductItems(items, productId, addItemSeqs); + addShopProductItems.addAll(items); + + // 处理图片 + if(CollUtil.isNotEmpty(newShopProductImageList)){ + processProductImages(newShopProductImageList.get(i), productId,base.getStore_id()); + } + + // 处理辅助属性 + if(CollUtil.isNotEmpty(newShopProductAssistIndexList)){ + processAssistIndices(newShopProductAssistIndexList, base.getStore_id(),false); + } + + // 准备分析数据 + ShopProductAnalytics shopProductAnalytics= new ShopProductAnalytics(); + shopProductAnalytics.setProduct_id(productId); + shopProductAnalytics.setProduct_click(0); + addAnalyticsList.add(shopProductAnalytics); + } + List itemIds = processProductItemsId(addShopProductItems, addItemSeqs); + addItemIds.addAll(itemIds); + // 2. 批量更新 + if (CollUtil.isNotEmpty(newProducts)) { + // new Thread(() -> { + logger.info("保存任务开始执行"); + try { + long startTime=System.nanoTime(); + saveBatch(newProducts,newProducts.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newProducts--{}条数据耗时:{}",newProducts.size(),duration/1000000000); + latch.countDown(); + } catch (Exception e) { + latch.countDown(); + logger.error("系统异常"+e.getMessage()); + } + // }).start(); + }else{ + // latch.countDown(); + } + }else { + //latch.countDown(); + } + if (CollUtil.isNotEmpty(updateProducts)) { + for(int i=0;i items = udpateShopProductItemList.get(i); + processProductItems(items, productId, updateItemSeqs);// + updateShopProductItems.addAll(items); + //allItemIds.addAll(itemIds); + // productToItemsMap.put(productId, itemIds); + + // 处理图片 + if(CollUtil.isNotEmpty(udpteShopProductImageList)){ + processProductImages(udpteShopProductImageList.get(i), productId,base.getStore_id()); + } + + // 处理辅助属性 + if(CollUtil.isNotEmpty(udpateShopProductAssistIndexList)){ + processAssistIndices(udpateShopProductAssistIndexList, base.getStore_id(),true); + } + + // 准备分析数据 + ShopProductAnalytics shopProductAnalytics= new ShopProductAnalytics(); + shopProductAnalytics.setProduct_id(productId); + shopProductAnalytics.setProduct_click(0); + udpateAnalyticsList.add(shopProductAnalytics); + } + List itemIds = processProductItemsId(updateShopProductItems, updateItemSeqs); + udpateItemIds.addAll(itemIds); + // 2. 批量更新 + if (CollUtil.isNotEmpty(updateProducts)) { + // new Thread(() -> { + logger.info("更新任务开始执行"); + try { + long startTime=System.nanoTime(); + updateBatchById(updateProducts); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateProducts-{}条数据耗时:{}",updateProducts.size(),duration/1000000000); + latch.countDown(); + } catch (Exception e) { + latch.countDown(); + logger.error("系统异常"+e.getMessage()); + } + // }).start(); + }else { + //latch.countDown(); + } + }else { + // latch.countDown(); + } + // latch.await(); + // 3. 处理其他表的批量操作(同样需要区分新增和更新) + batchProcessOtherTables(newShopProductIndexList,updateShopProductIndexList,newShopProductDataList,updateShopProductDataList, + newShopProductDetailList,updateShopProductDetailList,newShopProductInfoList,updateShopProductInfoList, + newShopProductValidPeriodList,updateShopProductValidPeriodList,addShopProductItems,updateShopProductItems, + addAnalyticsList,udpateAnalyticsList,addItemSeqs,updateItemSeqs); + logger.info("处理成功,新增{}条,更新{}条", newProducts.size(), updateProducts.size()); + return Pair.of(true, String.format("处理成功,新增%d条,更新%d条", + newProducts.size(), updateProducts.size())); + } catch (RuntimeException e) { + status.setRollbackOnly(); + logger.error("批量操作异常", e); + return Pair.of(false, "批量操作异常: " + e.getMessage()); + } +// catch (InterruptedException e) { +// status.setRollbackOnly(); +// logger.error("批量操作异常", e); +// return Pair.of(false, "批量操作异常: " + e.getMessage()); +// } + }); + + + } + + // 批量保存操作 + private void batchProcessOtherTables(List newShopProductIndex, List updateShopProductIndex, + List newShopProductDataList, List updateShopProductDataList, + List newshopProductDetailList, List updateShopProductDetailList, + List newShopProductInfoList,List updateShopProductInfoList, + List newShopProductValidPeriodList,List updateShopProductValidPeriodList, + List newshopProductItemList,List updateshopProductItemList, + List newShopProductAnalyticList,List updateShopProductAnalyticList, + List newShopProductItemSeqList,List updateShopProductItemSeqList) { + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); + transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); + transactionTemplate.setTimeout(60); // 60秒超时 + transactionTemplate.execute(status -> { + // 并行执行批量保存 +//CompletableFuture future1 = CompletableFuture.runAsync(() -> { + try { + if (CollUtil.isNotEmpty(newShopProductIndex)) { + // synchronized (this){ + long startTime=System.nanoTime(); + shopProductIndexService.saveBatch(newShopProductIndex,newShopProductIndex.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newShopProductIndex-{}条数据耗时:{}",newShopProductIndex.size(),duration/1000000000); + + //} + + } + if (CollUtil.isNotEmpty(updateShopProductIndex)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductIndexService.updateBatchById(updateShopProductIndex); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductIndex-{}条数据耗时:{}",updateShopProductIndex.size(),duration/1000000000); + // } + } + + if (CollUtil.isNotEmpty(newShopProductDataList)) { + //synchronized (this) { + long startTime=System.nanoTime(); + shopProductDataService.saveBatch(newShopProductDataList, newShopProductDataList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newShopProductDataList-{}条数据耗时:{}",newShopProductDataList.size(),duration/1000000000); + //} + } + if (CollUtil.isNotEmpty(updateShopProductDataList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductDataService.updateBatchById(updateShopProductDataList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductDataList-{}条数据耗时:{}",updateShopProductDataList.size(),duration/1000000000); + // } + } + }catch (RuntimeException e){ + logger.info("批量报错附表失败{}",e.getMessage()); + } + + // }); + + // CompletableFuture future2 = CompletableFuture.runAsync(() -> { + try { + if (CollUtil.isNotEmpty(newshopProductDetailList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductDetailService.saveBatch(newshopProductDetailList, newshopProductDetailList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newshopProductDetailList-{}条数据耗时:{}",newshopProductDetailList.size(),duration/1000000000); + + // } + } + if (CollUtil.isNotEmpty(updateShopProductDetailList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductDetailService.updateBatchById(updateShopProductDetailList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductDetailList-{}条数据耗时:{}",updateShopProductDetailList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(newShopProductInfoList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductInfoService.saveBatch(newShopProductInfoList, newShopProductInfoList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增updateShopProductDetailList-{}条数据耗时:{}",newShopProductInfoList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(updateShopProductInfoList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductInfoService.updateBatchById(updateShopProductInfoList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductInfoList-{}条数据耗时:{}",updateShopProductInfoList.size(),duration/1000000000); + // } + } + }catch (RuntimeException e){ + logger.info("批量报错附表失败{}",e.getMessage()); + } + //}); + + //CompletableFuture future3 = CompletableFuture.runAsync(() -> { + try { + if (CollUtil.isNotEmpty(newShopProductValidPeriodList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + validPeriodService.saveBatch(newShopProductValidPeriodList, newShopProductValidPeriodList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newShopProductValidPeriodList-{}条数据耗时:{}",newShopProductValidPeriodList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(updateShopProductValidPeriodList)) { + //synchronized (this) { + long startTime=System.nanoTime(); + validPeriodService.updateBatchById(updateShopProductValidPeriodList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductValidPeriodList-{}条数据耗时:{}",updateShopProductValidPeriodList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(newShopProductAnalyticList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductAnalyticsService.saveBatch(newShopProductAnalyticList, newShopProductAnalyticList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newShopProductAnalyticList-{}条数据耗时:{}",newShopProductAnalyticList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(updateShopProductAnalyticList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductAnalyticsService.updateBatchById(updateShopProductAnalyticList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductAnalyticList-{}条数据耗时:{}",updateShopProductAnalyticList.size(),duration/1000000000); + // } + } + }catch (RuntimeException e){ + logger.info("批量报错附表失败{}",e.getMessage()); + } + + //}); + + //CompletableFuture future4 = CompletableFuture.runAsync(() -> { + try { + if (CollUtil.isNotEmpty(newshopProductItemList)) { + // synchronized (this) { + long startTime=System.nanoTime(); + shopProductItemService.saveBatch(newshopProductItemList, newshopProductItemList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新增newshopProductItemList-{}条数据耗时:{}",newshopProductItemList.size(),duration/1000000000); + //} + } + if (CollUtil.isNotEmpty(updateshopProductItemList)) { + // synchronized (this) { + long startTime = System.nanoTime(); + shopProductItemService.updateBatchById(updateshopProductItemList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateshopProductItemList-{}条数据耗时:{}",updateshopProductItemList.size(),duration/1000000000); + //} + } + if (CollUtil.isNotEmpty(newShopProductItemSeqList)) { + // synchronized (this) { + long startTime = System.nanoTime(); + shopProductItemSeqService.saveBatch(newShopProductItemSeqList, newShopProductItemSeqList.size()); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("新曾newShopProductItemSeqList-{}条数据耗时:{}",newShopProductItemSeqList.size(),duration/1000000000); + // } + } + if (CollUtil.isNotEmpty(updateShopProductItemSeqList)) { + // synchronized (this) { + long startTime = System.nanoTime(); + shopProductItemSeqService.updateBatchById(updateShopProductItemSeqList); + long endTime = System.nanoTime(); + long duration = (endTime - startTime); + logger.info("更新updateShopProductItemSeqList-{}条数据耗时:{}",updateShopProductItemSeqList.size(),duration/1000000000); + // } + } + }catch (RuntimeException e){ + logger.info("批量报错附表失败{}",e.getMessage()); + } + //}); + // 等待所有操作完成 + // CompletableFuture.allOf(future1, future2, future3, future4).join(); + return null; + }); + + } + + /** + * 批量生产itemid + * @param items + * @param itemSeqs + * @return + */ + private List processProductItemsId(List items,List itemSeqs){ + List itemIds = new ArrayList<>(); + if (CollUtil.isEmpty(items)) return itemIds; + List generatedIds = shopNumberSeqService.batchCreateNextNo("item_id", items.size()); + for (int i = 0; i < items.size(); i++) { + Long itemId = generatedIds.get(i); + ShopProductItem item = items.get(i); + item.setItem_id(itemId); + itemIds.add(itemId); + ShopProductItemSeq field_row= itemSeqs.get(i); + field_row.setItem_id(itemId); + + } + + return itemIds; + } + + // 处理商品项 + private void processProductItems(List items, Long productId, + List itemSeqs) { + + for (int i = 0; i < items.size(); i++) { + ShopProductItem item = items.get(i); + item.setProduct_id(productId); + // itemIds.add(itemId); + + // ITEM_ID/SKU唯一编号表。 + // product_id + sort(spec_item_id) = 构造唯一ITEM ID + String item_spec = item.getItem_spec(); + cn.hutool.json.JSONArray array_item_spec = cn.hutool.json.JSONUtil.parseArray(item_spec); + List spec_item_ids = new ArrayList<>(); + List item_names = new ArrayList<>(); + for (Object josn_item_spec : array_item_spec) { + cn.hutool.json.JSONObject itemJ = (cn.hutool.json.JSONObject) ((cn.hutool.json.JSONObject) josn_item_spec).get("item"); + Integer id = Convert.toInt(itemJ.get("id")); + String name = Convert.toStr(itemJ.get("name")); + if (ObjectUtil.isNotNull(id)) spec_item_ids.add(id); + item_names.add(name); + } + + if (CollUtil.isNotEmpty(spec_item_ids)) Collections.sort(spec_item_ids); + + //用来判断是否使用 + item.setSpec_item_ids(CollUtil.join(spec_item_ids, ",")); + + // 创建itemSeq记录 + String skuUniqid = generateSkuUniqid(item); // 生成SKU唯一标识 + String seqVal = productId + ":" + skuUniqid; + ShopProductItemSeq field_row = new ShopProductItemSeq(); + field_row.setProduct_id(productId); + field_row.setProduct_item_seq_val(seqVal); + field_row.setProduct_item_seq_id(SecureUtil.md5(seqVal)); + //field_row.setItem_id(itemId); + + // 修正默认价格, 防止出现不合理价格 + BigDecimal item_platform_price = NumberUtil.max(item.getItem_cost_price(), item.getItem_platform_price()); + BigDecimal _item_unit_price = NumberUtil.max(item.getItem_unit_price(), item.getItem_platform_price()); + item.setItem_platform_price(item_platform_price); + item.setItem_unit_price(_item_unit_price); + item.setItem_name(CollUtil.join(item_names, ",")); + item.setItem_title(""); + item.setItem_freetime(0); + + itemSeqs.add(field_row); + } + } + + /** + * 生成SKU唯一标识符 + * @param item 商品项 + * @return SKU唯一标识字符串 + */ + private String generateSkuUniqid(ShopProductItem item) { + // 1. 获取商品规格信息 + String itemSpec = item.getItem_spec(); + if (StrUtil.isBlank(itemSpec)) { + return "default"; // 无规格商品的默认标识 + } + + // 2. 解析规格JSON + cn.hutool.json.JSONArray specArray; + try { + specArray = JSONUtil.parseArray(itemSpec); + } catch (Exception e) { + logger.warn("商品规格解析失败,使用默认标识", e); + return "default"; + } + + // 3. 提取所有规格项ID并排序 + List specItemIds = new ArrayList<>(); + for (Object specObj : specArray) { + JSONObject spec = (JSONObject) specObj; + JSONObject specItem = spec.getJSONObject("item"); + if (specItem != null) { + Integer id = specItem.getInteger("id"); + if (id != null) { + specItemIds.add(id); + } + } + } + + // 4. 排序确保顺序一致性 + Collections.sort(specItemIds); + + // 5. 生成唯一标识字符串 + return CollUtil.join(specItemIds, "-"); + } + + + + /** + * 检查哪些商品已存在 + */ + private Map checkExistingProducts(List productBases) { + // 1. 按店铺和货号分组 + Map> storeProductMap = productBases.stream() + .collect(Collectors.groupingBy( + p -> p.getStore_id() + "_" + p.getProduct_number() + )); + + // 2. 批量查询已存在的商品 + List> storeProductPairs = productBases.stream() + .map(p -> Pair.of(p.getStore_id(), p.getProduct_number())) + .distinct() + .collect(Collectors.toList()); + + // 3. 批量查询(优化为一次查询) + List existing = batchGetByStoreAndProductNumber(storeProductPairs,productBases.get(0).getStore_id()); + + // 4. 构建存在商品的映射表 + return existing.stream() + .collect(Collectors.toMap( + p -> p.getStore_id() + "_" + p.getProduct_number(), + ShopProductBase::getProduct_id + )); + } + + + /** + * 批量根据店铺和货号查询商品 + */ + private List batchGetByStoreAndProductNumber(List> storeProductPairs,Integer storeId) { + if (CollUtil.isEmpty(storeProductPairs)) { + return Collections.emptyList(); + } + + // 使用IN查询优化(根据数据库特性可能需要分批) + QueryWrapper query = new QueryWrapper<>(); + query.select("product_id", "store_id", "product_number"); + + // 构建OR条件 (store_id=X AND product_number=Y) OR (store_id=A AND product_number=B)... + storeProductPairs.forEach(pair -> { + query.or(q -> q.eq("store_id", pair.getFirst()) + .eq("product_number", pair.getSecond())); + }); + + return list(query); + } + + + /** + * 处理商品图片批量操作 + * @param productImages 商品图片列表 + * @param productId 商品ID + */ + private void processProductImages(List productImages, Long productId, Integer storeId) { + if (CollUtil.isEmpty(productImages)) { + return; + } + + // 1. 查询现有图片 + List existingImages = shopProductImageService.getShopProductImageByStoreId(storeId); + Map existingImageMap = existingImages.stream() + .collect(Collectors.toMap(ShopProductImage::getProduct_image_id, Function.identity())); + + // 2. 分离需要新增、更新和删除的图片 + List toAdd = new ArrayList<>(); + List toUpdate = new ArrayList<>(); + List toDelete = new ArrayList<>(); + List delBaiduImages = new ArrayList<>(); + List addBaiduImages = new ArrayList<>(); + + for (ShopProductImage newImage : productImages) { + newImage.setProduct_id(productId); + // 设置默认值 + newImage.setItem_image_ext_1(""); + newImage.setItem_image_ext_2(""); + + // 判断是新增还是更新 + if (newImage.getProduct_image_id() == null) { + toAdd.add(newImage); + if (StrUtil.isNotBlank(newImage.getItem_image_default())) { + addBaiduImages.add(newImage.getItem_image_default()); + } + } else { + ShopProductImage oldImage = existingImageMap.get(newImage.getProduct_image_id()); + if (oldImage != null) { + // 检查图片是否有变化 + if (!StrUtil.equals(oldImage.getItem_image_default(), newImage.getItem_image_default())) { + if (StrUtil.isNotBlank(oldImage.getItem_image_default())) { + delBaiduImages.add(oldImage.getItem_image_default()); + } + if (StrUtil.isNotBlank(newImage.getItem_image_default())) { + addBaiduImages.add(newImage.getItem_image_default()); + } + } + toUpdate.add(newImage); + } + } + } + + // 找出需要删除的图片(存在但不在新列表中) + existingImages.forEach(oldImage -> { + boolean stillExists = productImages.stream() + .anyMatch(img -> Objects.equals(img.getProduct_image_id(), oldImage.getProduct_image_id())); + if (!stillExists) { + toDelete.add(oldImage.getProduct_image_id()); + if (StrUtil.isNotBlank(oldImage.getItem_image_default())) { + delBaiduImages.add(oldImage.getItem_image_default()); + } + } + }); + + // 3. 执行批量操作 + if (CollUtil.isNotEmpty(toAdd)) { + shopProductImageService.saveBatch(toAdd,toAdd.size()); + } + if (CollUtil.isNotEmpty(toUpdate)) { + shopProductImageService.updateBatchById(toUpdate); + } + if (CollUtil.isNotEmpty(toDelete)) { + shopProductImageService.removeByIds(toDelete); + } + + } + /** + * 处理商品辅助属性批量操作 + * @param assistIndices 辅助属性列表 + * @param storeId 商品ID + */ + private void processAssistIndices(List assistIndices, Integer storeId,boolean isUpdate) { + if (CollUtil.isEmpty(assistIndices)) { + return; + } + // 查询现有辅助属性 + // QueryWrapper query = new QueryWrapper<>(); + //query.eq("product_id", productId); + List existingAssists = assistIndexService.getShopProductAssistIndexStoreId(storeId); + + // 分离需要新增、更新和删除的辅助属性 + List toDelete = new ArrayList<>(); + // 找出需要删除的辅助属性(存在但不在新列表中) + existingAssists.forEach(oldAssist -> { + boolean stillExists = assistIndices.stream() + .anyMatch(a -> Objects.equals( + a.getProduct_assist_index_id(), + oldAssist.getProduct_assist_index_id() + )); + if (!stillExists) { + toDelete.add(oldAssist.getProduct_assist_index_id()); + } + }); + + // 执行批量操作 + if (CollUtil.isNotEmpty(assistIndices)) { + if(isUpdate){ + assistIndexService.updateBatchById(assistIndices); + }else { + assistIndexService.saveBatch(assistIndices,assistIndices.size()); + } + + } + + if (CollUtil.isNotEmpty(toDelete)) { + assistIndexService.removeByIds(toDelete); + } + } + + + // +// private void myShopProductBaseBatch(List list){ +// SqlSession sqlSession=sqlSessionFactory.openSession(); +// StopWatch stopWatch=new StopWatch(); +// stopWatch.start(); +// shopProductBaseService.saveBatch(list); +// sqlSession.commit(); +// stopWatch.stop(); +// } + + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductImageServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductImageServiceImpl.java index d1f10917..4a6854fc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductImageServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductImageServiceImpl.java @@ -1,11 +1,18 @@ package com.suisung.mall.shop.product.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.product.ShopProductImage; +import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.product.mapper.ShopProductImageMapper; import com.suisung.mall.shop.product.service.ShopProductImageService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; +import java.util.Map; + /** *

@@ -17,4 +24,26 @@ import org.springframework.stereotype.Service; */ @Service public class ShopProductImageServiceImpl extends BaseServiceImpl implements ShopProductImageService { + + @Autowired + private RedisService redisService; + + @Override + public List getShopProductImageByStoreId(Integer storeId) { + + List existingImages = (List) redisService.get("ShopProductImageStoreId:"+storeId); + if(existingImages==null){ + QueryWrapper query = new QueryWrapper<>(); + query.eq("store_id", storeId); + existingImages = this.list(query); + redisService.set(""+storeId, existingImages); + } + + return existingImages; + } + + @Override + public void clearCacheShopProductImageByStoreId(Integer storeId) { + redisService.del("ShopProductImageStoreId:"+storeId); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/BaseDao.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/BaseDao.java new file mode 100644 index 00000000..315034ea --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/BaseDao.java @@ -0,0 +1,148 @@ +package com.suisung.mall.shop.sixun.dao; + +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; +import com.microsoft.sqlserver.jdbc.SQLServerException; +import com.suisung.mall.shop.sixun.dto.ResultDto; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +@Slf4j +public class BaseDao { + + private final static String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + private final static String DEFAULT_IP="127.0.0.1"; + private final static String DEFAULT_DATABASE="hbposev9"; + private final static String DEFAULT_USERNAME="sa"; + private final static String DEFAULT_PWD="123456"; + private final static int PortNumber=1433; + private final static int LoginTimeout=10; + /** + * + * 动态获取数据库连接 + * @param ip 数据库ip+ + * @param username 用户名 + * @param password 密码 todo 需要加密 + * @param dataBaseName 数据库名称 + * @return + */ + public Connection getConnection(String ip, String username, String password, String dataBaseName){ + Connection conn=null; + SQLServerDataSource sqlServerDataSource=new SQLServerDataSource(); + sqlServerDataSource.setDatabaseName(dataBaseName==null?DEFAULT_DATABASE:dataBaseName); + sqlServerDataSource.setServerName(ip==null?DEFAULT_IP:ip); + sqlServerDataSource.setPortNumber(PortNumber); + sqlServerDataSource.setLoginTimeout(LoginTimeout); + sqlServerDataSource.setPassword(password==null?DEFAULT_PWD:password); + sqlServerDataSource.setUser(username==null?DEFAULT_USERNAME:username); + try { + conn=sqlServerDataSource.getConnection(); + } catch (SQLServerException e) { + log.info("数据库连接异常方法{}异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getConnection",e.getMessage()); + throw new RuntimeException(e); + } + + return conn; + } + + /** + * 关闭数据库连接 + * @param conn + */ + public void Close(Connection conn){ + if(conn!=null){ + try { + conn.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + /** + * 返回游标和连接 减少服务器的占用内存 + * @param ip + * @param username + * @param password + * @param dataBaseName + * @return ResultDto + */ + public ResultDto baseFindList(String ip, String username, String password, String dataBaseName, String table){ + Connection connection=getConnection(ip,username,password,dataBaseName); + String sql="select * from %s where 1=1"; + sql=String.format(sql, table); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindList",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + + } + + /** + * 带分页数据 + * @param ip + * @param username + * @param password + * @param dataBaseName + * @param table + * @return + */ + public ResultDto baseFindListPage(String ip, String username, String password, String dataBaseName, String table,String orderColumn, int pageNo, int pageSize){ + Connection connection=getConnection(ip,username,password,dataBaseName); + int start=(pageNo-1)*pageSize+1; + int end=pageNo*pageSize; + String sql=" select * from( " + + " select ROW_NUMBER() OVER(ORDER BY %s) as rowId,* from %s " + + " ) as r where rowId between %s and %s"; + sql=String.format(sql, orderColumn,table,start,end); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindListPage",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + } + + public Integer getBaseTotal(String ip, String username, String password, String dataBaseName, String table){ + int total=0; + Connection connection=getConnection(ip,username,password,dataBaseName); + try { + String sql="select count(*) from %s where 1=1"; + sql=String.format(sql, table); + PreparedStatement ps= connection.prepareStatement(sql); + ResultSet rs=ps.executeQuery(); + while (rs.next()){ + total=rs.getInt(1); + } + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getBaseTotal",e.getMessage()); + throw new RuntimeException(e); + } + finally { + try { + connection.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return total; + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/SxDataDao.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/SxDataDao.java new file mode 100644 index 00000000..0e334389 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dao/SxDataDao.java @@ -0,0 +1,238 @@ +package com.suisung.mall.shop.sixun.dao; + +import com.suisung.mall.common.modules.sixun.SxSyncCategory; +import com.suisung.mall.common.modules.sixun.SxSyncGoods; +import com.suisung.mall.common.modules.sixun.SxSyncVip; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; +import com.suisung.mall.shop.sixun.dto.ResultDto; +import com.suisung.mall.shop.sixun.dto.SxCategoryModel; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * 考虑到每个思迅软件都是自己的数据,所以采用动态获取的方式获取数据 + * 数据库为MS SQL + * todo 如果考虑到数据量需要分页多线程 + */ +@Service +public class SxDataDao extends BaseDao{ + + private final static String T_BD_ITEM_CLS="t_bd_item_cls";//商品分类 + private final static String T_BD_ITEM_INFO="t_bd_item_info";//商品表 + private final static String RM_VIP_INFO="rm_vip_info";//会员表 + + private final static String ITEM_CLSNO="item_clsno";//商品分类排序字段 + private final static String ITEM_NO="item_no";//商品排序字段 + private final static String CARD_ID="card_id";//会员表排序字段 + + public final static Integer PAGESIZE=500; + + public final static String DEFAULT_IMG="https://digitalassets.tesla.com/tesla-contents/image/upload/f_auto,q_auto/Homepage-Model-Y-2-Promo-Hero-Tablet-CN.png"; + + + /** + * 查找商品分类数据 + * @param ip + * @param username + * @param password + * @param dataBaseName + */ + public void findTBdItemClsList(String ip,String username,String password,String dataBaseName){ + ResultDto resultDto=baseFindList(ip,username,password,dataBaseName,T_BD_ITEM_CLS); + ResultSet rs= resultDto.getResultSet(); + try { + while (rs.next()) { + System.out.printf(rs.getString("item_clsno"));//分类编码 + System.out.printf(rs.getString("item_clsname")+"\t");//分类名称 + System.out.print(rs.getString("cls_parent")+"\t");//父级编码 + System.out.print(rs.getString("item_flag")+"\t" + "\n");//显示标识 + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + /** + * 分页查找商品分类数据 + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findTBdItemClsListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){ + ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,ITEM_CLSNO,pageNo,pageSize); + ResultSet rs= resultDto.getResultSet(); + List sxSyncCategories=new ArrayList<>(); + SxSyncCategory sxSyncCategory=null; + try { + while (rs.next()) { + sxSyncCategory=new SxSyncCategory(); + sxSyncCategory.setItem_clsname(rs.getString("item_clsname"));//分类名称 + sxSyncCategory.setCls_parent(rs.getString("cls_parent"));//父级编码 + sxSyncCategory.setItem_clsno(rs.getString("item_clsno"));//分类编码 +// System.out.printf(rs.getString("item_clsno"));//分类编码 +// System.out.printf(rs.getString("item_clsname")+"\t");//分类名称 +// System.out.print(rs.getString("cls_parent")+"\t");//父级编码 +// System.out.print(rs.getString("item_flag")+"\t" + "\n");//显示标识 + sxSyncCategories.add(sxSyncCategory); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return sxSyncCategories; + } + + /** + * 获取商品分类TBdItemCls表的数量 + * @param dataBaseInfo + * @return + */ + public Integer getTBdItemClsTotal(DataBaseInfo dataBaseInfo){ + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS); + } + + /** + * 获取商品表t_bd_item_info表的数量 + * @param dataBaseInfo + * @return + */ + public int getTBditemInfoTotal(DataBaseInfo dataBaseInfo){ + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),ITEM_NO); + } + + /** + * 获取会员表t_rm_vip_info表的数量 + * @param dataBaseInfo + * @return + */ + public int getTrmVipInfoTotal(DataBaseInfo dataBaseInfo){ + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),CARD_ID); + } + + + /** + * 分页查找商品数据 + * 表T_BD_ITEM_INFO + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findBditemInfoListPage(DataBaseInfo dataBaseInfo,int pageNo,int pageSize){ + ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_INFO,ITEM_CLSNO,pageNo,pageSize); + ResultSet rs= resultDto.getResultSet(); + List sxSyncGoodses=new ArrayList<>(); + SxSyncGoods sxSyncGoods=null; + try { + while (rs.next()) { + BigDecimal price=new BigDecimal(rs.getString("price")); + BigDecimal salePrice=new BigDecimal(rs.getString("sale_price")); + BigDecimal gross= salePrice.subtract(price).divide(salePrice,2, RoundingMode.HALF_UP); + sxSyncGoods=new SxSyncGoods(); + sxSyncGoods.setItem_no(rs.getString("item_no"));//货号 + sxSyncGoods.setItem_subname(rs.getString("item_subname"));//商品名称 + sxSyncGoods.setItem_subno(rs.getString("item_subno"));//商品条码 + sxSyncGoods.setBig_cls_name("9999");//商品大类 todo 如何关联 + sxSyncGoods.setSmall_cls_name("9999");//商品小类 todo 如何关联 + sxSyncGoods.setItem_size(rs.getString("item_size"));//规格 + sxSyncGoods.setUnit_no(rs.getString("unit_no"));//单位 todo + sxSyncGoods.setStock(rs.getBigDecimal("item_flag"));//库存数量 todo item_stock? + + + sxSyncGoods.setGross_margin(gross);//毛利率 todo + sxSyncGoods.setPrice(rs.getBigDecimal("price"));//进货价 + sxSyncGoods.setSale_price(rs.getBigDecimal("sale_price"));//零售价 + + sxSyncGoods.setVip_price(rs.getBigDecimal("vip_price"));//会员价 + sxSyncGoods.setVip_acc_flag(rs.getBigDecimal("vip_acc_flag"));//允许积分 + sxSyncGoods.setVip_acc_num(rs.getBigDecimal("vip_acc_num"));//积分值 + sxSyncGoods.setSale_flag(rs.getInt("main_Sale_flag"));//商品状态 todo 是main_Sale_flag? + sxSyncGoods.setItem_rem(rs.getString("item_rem"));//助记码 + sxSyncGoods.setBuild_date(rs.getString("build_date"));//生产日期 + sxSyncGoods.setValid_days(rs.getString("item_flag"));//保质期 todo stop_date-build_date? + + sxSyncGoodses.add(sxSyncGoods); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return sxSyncGoodses; + } + + + /** + * 分页查找会员数据 + * RM_VIP_INFO + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findRmVipInfoListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){ + ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDataBaseName(),RM_VIP_INFO,CARD_ID,pageNo,pageSize); + ResultSet rs= resultDto.getResultSet(); + List sxSyncVips=new ArrayList<>(); + SxSyncVip sxSyncVip=null; + try { + while (rs.next()) { + sxSyncVip = new SxSyncVip(); + int cardStatus=rs.getInt("card_status"); + if(cardStatus!=1){ + sxSyncVip.setVip_name(rs.getString("vip_name"));//会员名称 + sxSyncVip.setVip_sex(rs.getString("vip_sex"));//会员名称 + sxSyncVip.setMobile(rs.getString("mobile"));//会员名称 + sxSyncVip.setBirthday(rs.getString("birthday"));//会员生日 + sxSyncVip.setCard_type(rs.getString("card_type")==null?"v1":rs.getString("card_type"));//会员生日 + sxSyncVip.setCard_no(rs.getString("card_no"));//会员卡号 + sxSyncVip.setCard_no(rs.getString("now_acc_num"));//会员积分 + sxSyncVip.setCard_no(rs.getString("residual_amt"));//储值余额 + sxSyncVip.setCard_no(rs.getString("vip_start_date"));//建档日期 + + System.out.println(rs.getString("vip_name"));//会员名称 + System.out.println(rs.getString("mobile"));//会员手机号 + System.out.println(rs.getString("vip_sex"));//会员性别 + System.out.println(rs.getString("birthday"));//会员生日 + System.out.println(rs.getString("card_no"));//会员卡号 + System.out.println(rs.getString("card_type"));//会员等级 + System.out.println(rs.getBigDecimal("residual_amt"));//储值余额 + System.out.println(rs.getBigDecimal("now_acc_num"));//会员积分 + System.out.println(rs.getString("vip_start_date"));//建档日期 + System.out.println(rs.getInt("card_status"));//会员状态 + } + + sxSyncVips.add(sxSyncVip); + } + }catch (SQLException e){ + throw new RuntimeException(e); + } + return sxSyncVips; + } + + + public static void main(String[] args) { + //new SxDataUtils().findTBdItemClsList("127.0.0.1","sa","123456","hbposev9"); + new SxDataDao().findTBdItemClsListPage(new DataBaseInfo(),4,10); + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/DataBaseInfo.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/DataBaseInfo.java new file mode 100644 index 00000000..2537931f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/DataBaseInfo.java @@ -0,0 +1,16 @@ +package com.suisung.mall.shop.sixun.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class DataBaseInfo { + @ApiModelProperty("数据库IP") + private String ip; + @ApiModelProperty("用户名") + private String userName; + @ApiModelProperty("密码") + private String password; + @ApiModelProperty("数据库名称") + private String dataBaseName; +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ProductImage.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ProductImage.java new file mode 100644 index 00000000..f7d48cdf --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ProductImage.java @@ -0,0 +1,17 @@ +package com.suisung.mall.shop.sixun.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class ProductImage { + @ApiModelProperty("图片路径") + private String image_url; + @ApiModelProperty("推荐值") + private String seq; + @ApiModelProperty("介绍") + private String desc; + @ApiModelProperty("是否默认") + private String is_default; + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/PromotionDetail.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/PromotionDetail.java new file mode 100644 index 00000000..021be2be --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/PromotionDetail.java @@ -0,0 +1,17 @@ +package com.suisung.mall.shop.sixun.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class PromotionDetail { + + @ApiModelProperty("活动id") + private String activity_id; + @ApiModelProperty("活动名称") + private String activity_name; + @ApiModelProperty("价格") + private String price; + @ApiModelProperty("介绍") + private String intro; +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ResultDto.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ResultDto.java new file mode 100644 index 00000000..f5059bca --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/ResultDto.java @@ -0,0 +1,15 @@ +package com.suisung.mall.shop.sixun.dto; + +import lombok.Data; + +import java.sql.Connection; +import java.sql.ResultSet; + +@Data +public class ResultDto { + + private Connection connection; + + private ResultSet resultSet; + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxCategoryModel.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxCategoryModel.java new file mode 100644 index 00000000..5775db46 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxCategoryModel.java @@ -0,0 +1,34 @@ +package com.suisung.mall.shop.sixun.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; + +/** + * 模型对应 + */ +@Data +public class SxCategoryModel { + //模型对应ShopBaseProductCategory start + private String parent_name;//暂时不用 + @NotEmpty + @ApiModelProperty(value = "商品分类名称") + private String category_name; + @ApiModelProperty(value = "分类图片") + private String category_image; + @ApiModelProperty(value = "是否允许虚拟商品(ENUM):1-是; 0-否") + private Integer category_virtual_enable; + @ApiModelProperty(value = "分佣比例-百分比") + private BigDecimal category_commission_rate; + // private String type_name;//todo 看代码没有用,使用的是product_type + //模型对应ShopBaseProductCategory end + @ApiModelProperty(value = "产品类型") + private String product_type; + @ApiModelProperty(value = "第一级父类") + private String first_category_name; + @ApiModelProperty(value = "第二级父类") + private String second_category_name; + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxGoosModel.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxGoosModel.java new file mode 100644 index 00000000..ea863797 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/dto/SxGoosModel.java @@ -0,0 +1,103 @@ +package com.suisung.mall.shop.sixun.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 思迅同步商品数据入口数据 + */ +@Data +public class SxGoosModel { + + @ApiModelProperty("商品名称") + private String product_name; + + @ApiModelProperty("商品货号") + private String product_number; + + @ApiModelProperty("商品条形码") + private String product_barcode; + + @ApiModelProperty("一级分类") + private String first_category_name; + + @ApiModelProperty("二级分类") + private String second_category_name; + + @ApiModelProperty("三级分类") + private String three_category_name; + + @ApiModelProperty("产品类型") + private String product_type; + + @ApiModelProperty("商品种类") + private String product_kind; + + @ApiModelProperty("成本价") + private BigDecimal cost_price; + + @ApiModelProperty("价格") + private BigDecimal price; + + @ApiModelProperty("原价") + private BigDecimal original_price; + + @ApiModelProperty("商品价格") + private BigDecimal retail_price; + + @ApiModelProperty("会员价") + private BigDecimal member_price; + + @ApiModelProperty("库存") + private BigDecimal stock; + + @ApiModelProperty("") + private BigDecimal gross_margin; + + @ApiModelProperty("规格单位") + private String unit; + + @ApiModelProperty("可用积分") + private BigDecimal can_piont; + + @ApiModelProperty("总积分") + private BigDecimal points; + + @ApiModelProperty("助记码") + private String mnemonic; + + + @ApiModelProperty("最大购买商品量") + private Integer buy_limit; + + @ApiModelProperty("品牌名称") + private String brand_name; + + @ApiModelProperty("标签") + private String tags; + + @ApiModelProperty("辅助属性") + private List product_assist; + + @ApiModelProperty("规格(JSON)-规格、规格值、goods_id 规格不需要全选就可以添加对应数据[") + private List product_spec; + + @ApiModelProperty("商品卖点特征") + private String product_value; + + @ApiModelProperty("商品视频") + private String product_video; + + @ApiModelProperty("产品描述") + private String product_desc; + + @ApiModelProperty("商品图片库") + private List product_images; + + + @ApiModelProperty("商品详情") + private List promotion_detail; +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncCategoryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncCategoryService.java index e4f2e2af..8ae201ba 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncCategoryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncCategoryService.java @@ -11,6 +11,8 @@ package com.suisung.mall.shop.sixun.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.sixun.SxSyncCategory; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; +import com.suisung.mall.shop.sixun.dto.SxCategoryModel; import java.util.List; @@ -82,4 +84,22 @@ public interface SxSyncCategoryService { * @return */ Boolean updateStatusBatch(List list, Integer status); + + /** + * 通过数据库获取店铺的商品分类 + * + * @param dataBaseInfo + * @return + */ + List getCategoryByDataBasePage( DataBaseInfo dataBaseInfo,int startPage,int pageSize); + + /** + * 通过数据库获取店铺的商品分类总数 + * @param dataBaseInfo + * @return + */ + Integer getCategoryTotal( DataBaseInfo dataBaseInfo); + + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncGoodsService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncGoodsService.java index 80a00e08..db5e7a33 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncGoodsService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncGoodsService.java @@ -11,6 +11,7 @@ package com.suisung.mall.shop.sixun.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.sixun.SxSyncGoods; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; import java.util.List; @@ -75,4 +76,20 @@ public interface SxSyncGoodsService { * @return */ IPage pageByStoreId(String storeId, Integer status, Integer pageNum, Integer pageSize); + + /** + * 通过思迅数据库获取店铺的商品总数 + * @param dataBaseInfo + * @return + */ + Integer getGoodsTotal(DataBaseInfo dataBaseInfo); + + /** + * 通过思迅数据库分页查找店铺的商品信息 + * @param dataBaseInfo + * @param pageNum + * @param pageSize + * @return + */ + List findGoodsListPage(DataBaseInfo dataBaseInfo,int pageNum,int pageSize); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncVipService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncVipService.java index 57648960..889dddef 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncVipService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/SxSyncVipService.java @@ -10,6 +10,7 @@ package com.suisung.mall.shop.sixun.service; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.sixun.SxSyncVip; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; import java.util.List; @@ -57,4 +58,18 @@ public interface SxSyncVipService { * @return */ SxSyncVip getByVipNo(String storeId, String vipNo); + + /** + * 通过数据库获取会员总数 + * @param dataBaseInfo + * @return + */ + Integer getVipMembersTotal( DataBaseInfo dataBaseInfo); + + /** + * 分页通过数据库获取会员数据 + * @param dataBaseInfo + * @return + */ + List findVipMemberPage( DataBaseInfo dataBaseInfo,int pageNum,int pageSize); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncCategoryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncCategoryServiceImpl.java index f46c1efc..b60372b4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncCategoryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncCategoryServiceImpl.java @@ -9,7 +9,9 @@ package com.suisung.mall.shop.sixun.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -20,17 +22,23 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.sixun.SxSyncCategory; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.sixun.dao.SxDataDao; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; +import com.suisung.mall.shop.sixun.dto.SxCategoryModel; import com.suisung.mall.shop.sixun.mapper.SxSyncCategoryMapper; import com.suisung.mall.shop.sixun.service.SxSyncCategoryService; import com.suisung.mall.shop.sixun.utils.CommonUtil; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; @Service public class SxSyncCategoryServiceImpl extends BaseServiceImpl implements SxSyncCategoryService { + @Resource + private SxDataDao sxDataDao; /** * 同步店铺的商品分类 * @@ -238,4 +246,74 @@ public class SxSyncCategoryServiceImpl extends BaseServiceImpl getCategoryByDataBasePage(DataBaseInfo dataBaseInfo,int startPage,int pageSize) { + List sxSyncCategories=sxDataDao.findTBdItemClsListPage(dataBaseInfo,startPage, pageSize); + if(CollectionUtil.isEmpty(sxSyncCategories)){ + return new ArrayList<>(); + } + List sxSyncCategoriesCp = new ArrayList<>(sxSyncCategories); + Iterator iterator= sxSyncCategories.iterator(); + List sxCategoryModels=new ArrayList<>(); + SxCategoryModel sxCategoryModel=null; + while (iterator.hasNext()){ + SxSyncCategory sxSyncCategory= iterator.next(); + sxCategoryModel=new SxCategoryModel(); + sxCategoryModel.setCategory_image(SxDataDao.DEFAULT_IMG); + sxCategoryModel.setCategory_name(sxSyncCategory.getItem_clsname()); + //寻找父级 + if(null!=sxSyncCategory.getCls_parent()){ + SxSyncCategory firstNode=getParentNode(sxSyncCategoriesCp,sxSyncCategory.getCls_parent()); + sxCategoryModel.setParent_name(firstNode.getItem_clsname());//todo 暂时无用 + //如何存在上级的上级,则上级为第二层,上上及为第一层 + if(null!=firstNode.getCls_parent()) {//还存在上级 + SxSyncCategory secondNode=getParentNode(sxSyncCategoriesCp,sxSyncCategory.getCls_parent()); + sxCategoryModel.setFirst_category_name(secondNode.getItem_clsname()); + sxCategoryModel.setSecond_category_name(firstNode.getItem_clsname()); + }else { + sxCategoryModel.setFirst_category_name(firstNode.getItem_clsname()); + } + } + sxCategoryModels.add(sxCategoryModel); + } + return sxCategoryModels; + } + + /** + * 通过流查找父节点 + * @param sxSyncCategories + * @param parentId + */ + private SxSyncCategory getParentNode(List sxSyncCategories,String parentId){ + List list= sxSyncCategories.stream().filter(cc-> + cc.getItem_clsno().trim().equals(parentId.trim())) + .collect(Collectors.toList()); + return CollectionUtil.isNotEmpty(list)?list.get(0):new SxSyncCategory(); + } + + @Override + public Integer getCategoryTotal(DataBaseInfo dataBaseInfo) { + // 记录总数 + return sxDataDao.getTBdItemClsTotal(dataBaseInfo); + } + + + public static void main(String[] args) { + List list= new SxSyncCategoryServiceImpl().getCategoryByDataBasePage(new DataBaseInfo(),1,50); + list.forEach(e->{ + System.out.println("node"+e.getCategory_name()+"--First_category_name--"+e.getFirst_category_name()+"--Second_category_name--"+e.getSecond_category_name()); + }); + } + + //########### 从思迅数据库获取数据区域 end } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncGoodsServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncGoodsServiceImpl.java index 5185e34f..ff2738c1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncGoodsServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncGoodsServiceImpl.java @@ -20,18 +20,22 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.sixun.SxSyncGoods; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.sixun.dao.SxDataDao; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; import com.suisung.mall.shop.sixun.mapper.SxSyncGoodsMapper; import com.suisung.mall.shop.sixun.service.SxSyncGoodsService; import com.suisung.mall.shop.sixun.utils.CommonUtil; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.util.Date; import java.util.List; import java.util.Objects; @Service public class SxSyncGoodsServiceImpl extends BaseServiceImpl implements SxSyncGoodsService { - + @Resource + private SxDataDao sxDataDao; /** * 同步记录 * @@ -185,7 +189,6 @@ public class SxSyncGoodsServiceImpl extends BaseServiceImpl(pageNum, pageSize), queryWrapper); } - // ########### 从思迅商锐9.7系统获取数据区域 开始 public List pageGoodsListFromSiXun(Integer pageNo, Integer pageSize) { @@ -223,5 +226,12 @@ public class SxSyncGoodsServiceImpl extends BaseServiceImpl findGoodsListPage(DataBaseInfo dataBaseInfo, int pageNum, int pageSize) { + return sxDataDao.findBditemInfoListPage(dataBaseInfo,pageNum,pageSize); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncVipServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncVipServiceImpl.java index e5f044e6..95f6d11f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncVipServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/service/impl/SxSyncVipServiceImpl.java @@ -18,18 +18,22 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.modules.sixun.SxSyncVip; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.sixun.dao.SxDataDao; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; import com.suisung.mall.shop.sixun.mapper.SxSyncVipMapper; import com.suisung.mall.shop.sixun.service.SxSyncVipService; import com.suisung.mall.shop.sixun.utils.CommonUtil; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.util.Date; import java.util.List; import java.util.Objects; @Service public class SxSyncVipServiceImpl extends BaseServiceImpl implements SxSyncVipService { - + @Resource + private SxDataDao sxDataDao; /** * 同步店铺的 * @@ -188,4 +192,14 @@ public class SxSyncVipServiceImpl extends BaseServiceImpl findVipMemberPage(DataBaseInfo dataBaseInfo,int pageNum,int pageSize) { + return sxDataDao.findRmVipInfoListPage(dataBaseInfo,pageNum,pageSize); + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sixun/utils/FileUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/utils/FileUtils.java new file mode 100644 index 00000000..a0eb6077 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sixun/utils/FileUtils.java @@ -0,0 +1,65 @@ +package com.suisung.mall.shop.sixun.utils; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.util.Calendar; + +@Component +public class FileUtils { + public static final String pathSeparator = System.getProperty("file.separator"); + public static final String GOODS = "goods"+pathSeparator;//商品 + public static final String CATEGORY= "category"+pathSeparator;//分类 + public static final String BRAND = "brand"+pathSeparator;//品牌 + public static final String MEMBER= "member"+pathSeparator;//会员 + + public String getSyncTypeFlag(String syncType,String path){ + Calendar calendar=Calendar.getInstance(); + int year=calendar.get(Calendar.YEAR); + int month=calendar.get(Calendar.MONTH)+1; + int date=calendar.get(Calendar.DAY_OF_MONTH); + String result = path+pathSeparator+"uploaded"+pathSeparator; + switch (syncType){ + case "1": + result+=GOODS; + break; + case "2": + result+=CATEGORY; + break; + case "3": + result+=BRAND; + break; + case "4": + result+=MEMBER; + break; + default: + break; + } + return result+year+pathSeparator+month+pathSeparator+date+pathSeparator; + } + + /** + * 创建文件 + * @param folderPath + * @param fileName + */ + public static String createFolderAndFileUsingFile(String folderPath, String fileName) { + String filePath = folderPath + fileName; + File folder = new File(folderPath); + if (!folder.exists()) { + folder.mkdirs(); + } + + File file = new File(filePath); + try { + if (!file.exists()) { + file.createNewFile(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BatchInsertUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BatchInsertUtils.java new file mode 100644 index 00000000..4a5f7951 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BatchInsertUtils.java @@ -0,0 +1,91 @@ +package com.suisung.mall.shop.sync.Utils; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.product.ShopProductBase; +import com.suisung.mall.shop.product.mapper.ShopProductBaseMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.lang.reflect.Method; +import java.util.List; + +@Component +@Slf4j +public class BatchInsertUtils { + private static final int DEFAULT_BATCH_SIZE = 1000; + + @Autowired + private SqlSessionFactory sqlSessionFactory; + /** + * 高性能批量插入 + */ + public static boolean batchInsert(Class mapperClass, List dataList, SqlSessionFactory sqlSessionFactory) { + return batchInsert(mapperClass, dataList, DEFAULT_BATCH_SIZE,sqlSessionFactory); + } + + public static boolean batchInsert(Class mapperClass, List dataList, int batchSize, SqlSessionFactory sqlSessionFactory) { + if (CollectionUtils.isEmpty(dataList)) { + return true; + } + + try (SqlSession sqlSession = SqlSessionUtils.getSqlSession( + sqlSessionFactory, + ExecutorType.BATCH, + null)) { + + BaseMapper mapper = (BaseMapper) sqlSession.getMapper(mapperClass); + int size = dataList.size(); + + for (int i = 0; i < size; i++) { + mapper.insert(dataList.get(i)); + // 分批提交 + if (i > 0 && i % batchSize == 0 || i == size - 1) { + sqlSession.flushStatements(); + } + } + return true; + } catch (Exception e) { + log.error("批量插入失败", e); + return false; + } + } + + /** + * 使用VALUES列表批量插入 + */ + public static boolean batchInsertWithValues(Class> mapperClass, + String methodName, + List dataList,SqlSessionFactory sqlSessionFactory) { + if (CollectionUtils.isEmpty(dataList)) { + return true; + } + + try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { + BaseMapper mapper = sqlSession.getMapper(mapperClass); + Method method = mapper.getClass().getMethod(methodName, List.class); + + int total = dataList.size(); + int batchCount = (total + DEFAULT_BATCH_SIZE - 1) / DEFAULT_BATCH_SIZE; + + for (int i = 0; i < batchCount; i++) { + int from = i * DEFAULT_BATCH_SIZE; + int to = Math.min(from + DEFAULT_BATCH_SIZE, total); + List subList = dataList.subList(from, to); + + method.invoke(mapper, subList); + sqlSession.flushStatements(); + } + return true; + } catch (Exception e) { + log.error("批量插入失败", e); + return false; + } + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/CryptoUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/CryptoUtils.java new file mode 100644 index 00000000..49170209 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/CryptoUtils.java @@ -0,0 +1,117 @@ +package com.suisung.mall.shop.sync.Utils; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class CryptoUtils { + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; + private static final String SECRET_KEY = "9f823ea6ab22785caf040e4cc3930619"; // 必须16/24/32字符 + + private static final String HASH_ALGORITHM_KEY = "appKey=a&sign=b&storeId=c"; + + /** + * 打包并加密字段 + */ + public static String packAndEncrypt(String appKey, String sign, String storeId) throws Exception { + String combined = String.format("appKey=%s&sign=%s&storeId=%s", appKey, sign, storeId); + return encrypt(combined); + } + + /** + * 32位字符串生成 + * @param input + * @return + * @throws NoSuchAlgorithmException + */ + public static String generate32CharMD5(String input) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hashBytes = md.digest(input.getBytes()); + + StringBuilder hexString = new StringBuilder(); + for (byte b : hashBytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + + /** + * 解密并解包字段 + */ + public static Map decryptAndUnpack(String encryptedData) throws Exception { + String decrypted = decrypt(encryptedData); + Map result = new HashMap<>(); + String[] pairs = decrypted.split("&"); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + result.put(keyValue[0], keyValue[1]); + } + } + return result; + } + + /** + * 加密 + * @param value + * @return + * @throws Exception + */ + private static String encrypt(String value) throws Exception { + SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + byte[] encryptedBytes = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(encryptedBytes); + } + + /** + * 解密 + * @param encryptedValue + * @return + * @throws Exception + */ + private static String decrypt(String encryptedValue) throws Exception { + SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + byte[] decodedBytes = Base64.getDecoder().decode(encryptedValue); + byte[] decryptedBytes = cipher.doFinal(decodedBytes); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } + + public static String dealBlankStr(String original) throws UnsupportedEncodingException { + return original.replaceAll(" ", "+"); + } + + + // 示例用法 + public static void main(String[] args) throws Exception { + + String appKey = "d68397c4fb671bc024e24e1964b067cc35388818"; + String sign = "d68397c4fb671bc024e24e1964b067cc35388818"; + String storeId = "1"; + + // 打包加密 + String encrypted = packAndEncrypt(appKey, sign, storeId); + System.out.println("加密结果: " + encrypted); + + // 解密解包 + Map result = decryptAndUnpack(encrypted); + System.out.println("解密结果: " + result); + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ThreadFileUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ThreadFileUtils.java new file mode 100644 index 00000000..790552d1 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ThreadFileUtils.java @@ -0,0 +1,37 @@ +package com.suisung.mall.shop.sync.Utils; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.rmi.RemoteException; + +@lombok.extern.slf4j.Slf4j +public class ThreadFileUtils { + + public JSONArray processFolder(String taskName, String folderPath) throws RuntimeException { + File folder = new File(folderPath); + if (!folder.exists() || !folder.isDirectory()) { + throw new RuntimeException("文件夹不存在或不是目录: " + folderPath); + } + + File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".txt")); + if (jsonFiles == null || jsonFiles.length == 0) { + log.info("[{}]文件夹中没有JSON文件: {}",taskName,folderPath); + return null; + } + File jsonFile=jsonFiles[0]; + JSONArray jsonArray =null; + try { + String content = new String(Files.readAllBytes(jsonFile.toPath()), StandardCharsets.UTF_8); + jsonArray = JSONUtil.parseArray(content); + log.info("[{}] 成功处理文件: {}",taskName,jsonFile.getAbsolutePath()); + } catch (RuntimeException | IOException e) { + throw new RuntimeException("处理文件 " + jsonFile.getName() + " 失败: " + e.getMessage(), e); + } + return jsonArray; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java new file mode 100644 index 00000000..f2a4daa3 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java @@ -0,0 +1,29 @@ +package com.suisung.mall.shop.sync.controller; + +import com.suisung.mall.shop.sync.service.SyncThirdDataService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = "第三方数据同步") +@Controller +@RequestMapping("/shop/sync/app") +public class ClientController { + + @Autowired + private SyncThirdDataService syncThirdDataService; + + @ApiOperation(value = "下载客户端应用", notes = "获取加密密钥") + @RequestMapping(value = "/downClientJar",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE, method = RequestMethod.GET) + public ResponseEntity downClientJar(@RequestParam String primaryKey) { + return syncThirdDataService.downloadToClient(primaryKey); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java new file mode 100644 index 00000000..e1745d30 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.controller; + +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.sync.StoreDbConfig; +import com.suisung.mall.common.modules.sync.SyncApp; +import com.suisung.mall.common.modules.sync.SyncFileLog; +import com.suisung.mall.shop.sync.service.StoreDbConfigService; +import com.suisung.mall.shop.sync.service.SyncFileLogService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 页面导航表 前端控制器 + *

+ * + * @author lyj + * @since 2025-05-16 + */ +@Api(tags = "页面导航表-店铺数据库连接配置") +@RestController +@RequestMapping("/admin/shop/shop-sync-storeDbConfig") +public class StoreDbConfigController { + + @Autowired + private StoreDbConfigService storeDbConfigService; + + /** + * 分页列表查询 + * @param storeDbConfig + * @param pageNum + * @param pageSize + * @return + */ + @ApiOperation(value = "列表查询-分页列表查询店铺数据库连接配置", notes = "列表查询-分页列表查询店铺数据库连接配置") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult list(@RequestBody StoreDbConfig storeDbConfig , + @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + return storeDbConfigService.findStoreDbConfigPageList(storeDbConfig, pageNum, pageSize); + } + + /** + * 单笔获取 + * @param storeDbConfig + * @return + */ + @ApiOperation(value = "单笔获取-分页列表查询店铺数据库连接配置", notes = "单笔获取-分页列表查询店铺数据库连接配置") + @RequestMapping(value = "/getStoreDbConfig", method = RequestMethod.GET) + public CommonResult getStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) { + return CommonResult.success(storeDbConfigService.getStroeConfig(storeDbConfig)); + } + + /** + * 新增 + * @param storeDbConfig + * @return + */ + @ApiOperation(value = "新增-店铺数据库连接配置", notes = "新增-店铺数据库连接配置") + @RequestMapping(value = "/saveStoreDbConfig", method = RequestMethod.POST) + public CommonResult saveStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) { + return storeDbConfigService.addStoreDbConfig(storeDbConfig); + } + + /** + * 更新 + * @param storeDbConfig + * @return + */ + @ApiOperation(value = "更新-店铺数据库连接配置", notes = "更新-店铺数据库连接配置") + @RequestMapping(value = "/udpateStoreDbConfig", method = RequestMethod.PUT) + public CommonResult udpateStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) { + return storeDbConfigService.updateStoreDbConfig(storeDbConfig); + } + + /** + * 删除 + * @param storeDbConfig + * @return + */ + @ApiOperation(value = "删除-店铺数据库连接配置", notes = "删除-店铺数据库连接配置") + @RequestMapping(value = "/delStoreDbConfig", method = RequestMethod.PUT) + public CommonResult delStoreDbConfig(@RequestBody StoreDbConfig storeDbConfig) { + return storeDbConfigService.delStoreDbConfig(storeDbConfig); + } + + /** + * 生产密钥,用来放到app/bin目录,替换原来的密钥 + * @param syncApp + * @return + */ + @ApiOperation(value = "客户端primaryKey.txt生产", notes = "密钥生成器") + @RequestMapping(value = "/getPrimaryKey", method = RequestMethod.PUT) + public String getPrimaryKey(@RequestBody SyncApp syncApp) { + return storeDbConfigService.getPrimaryKey(syncApp); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java index f0c71612..4a7eab46 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java @@ -10,22 +10,30 @@ package com.suisung.mall.shop.sync.controller; import cn.hutool.json.JSONArray; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.sync.StoreDbConfig; import com.suisung.mall.common.pojo.req.SyncThirdMemberReq; import com.suisung.mall.common.pojo.res.ThirdApiRes; +import com.suisung.mall.shop.sync.service.SyncAppService; import com.suisung.mall.shop.sync.service.SyncThirdDataService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.List; +import java.util.Map; @Api(tags = "第三方数据同步") @RestController @RequestMapping("/shop/sync/third") public class SyncThirdDataController { + @Resource + private SyncAppService syncAppService; + @Resource private SyncThirdDataService syncThirdDataService; @@ -82,4 +90,59 @@ public class SyncThirdDataController { return syncThirdDataService.syncManual(storeId, syncType); } + + @ApiOperation(value = "思迅文件上传", notes = "死讯软件客户端文件上传") + @RequestMapping(value = "/uploudSxData", method = RequestMethod.POST) + public ThirdApiRes uploudSxData(@RequestParam("file") MultipartFile file, + @RequestParam String appKey, + @RequestParam String sign, + @RequestParam String page, + @RequestParam String syncType) { + return syncThirdDataService.fileUpload(appKey,sign,page,syncType,file); + } + + @ApiOperation(value = "读取数据", notes = "当思迅发送完成数据后,调用该地址读取本地文件") + @RequestMapping(value = "/readSxData", method = RequestMethod.POST) + public ThirdApiRes readSxData(@RequestBody List folders, + @RequestParam String appKey, + @RequestParam String sign, + @RequestParam String syncType) { + new Thread(new Runnable() { + @Override + public void run() { + syncThirdDataService.SyncReadSxFileData(appKey,sign,syncType,folders); + } + }).start(); + return new ThirdApiRes().success("服务器已处理文件"); + } + + @ApiOperation(value = "读取数据", notes = "手动补偿商品同步失败的数据使用") + @RequestMapping(value = "/retryReadSxData", method = RequestMethod.POST) + public ThirdApiRes RetryReadSxData(@RequestParam List folders, + @RequestParam String appKey, + @RequestParam String sign, + @RequestParam String syncType) { + return readSxData(folders,appKey,sign,syncType); + } + + @ApiOperation(value = "获取加密密钥", notes = "获取加密密钥") + @RequestMapping(value = "/getAppSign", method = RequestMethod.POST) + public Map getAppSign(@RequestParam String primaryKey) { + return syncAppService.getAppSign(primaryKey); + } + + /** + * 客户端查询配置 + * @param appKey + * @param sign + * @return + */ + @ApiOperation(value = "客户端查询配置", notes = "客户端查询配置") + @RequestMapping(value = "/getStoreDbConfig", method = RequestMethod.POST) + public ThirdApiRes getStoreDbConfig(@RequestParam String appKey, + @RequestParam String sign){ + return syncThirdDataService.getStoreDbConfig(appKey,sign); + } + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java new file mode 100644 index 00000000..09483b2a --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java @@ -0,0 +1,6 @@ +package com.suisung.mall.shop.sync.keymanage; + +public class RedisKey { + + public static final String SXCLIENTKEYVERSION="sxclientKey:version"; +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/StoreDbConfigMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/StoreDbConfigMapper.java new file mode 100644 index 00000000..e836db91 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/StoreDbConfigMapper.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.sync.StoreDbConfig; +import com.suisung.mall.common.modules.sync.SyncFileLog; +import org.springframework.stereotype.Repository; + +@Repository +public interface StoreDbConfigMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/SyncFileLogMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/SyncFileLogMapper.java new file mode 100644 index 00000000..f6d38220 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/SyncFileLogMapper.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.sync.SyncFileLog; +import org.springframework.stereotype.Repository; + +@Repository +public interface SyncFileLogMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/pool/ThreadPoolManager.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/pool/ThreadPoolManager.java new file mode 100644 index 00000000..762ed133 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/pool/ThreadPoolManager.java @@ -0,0 +1,414 @@ +package com.suisung.mall.shop.sync.pool; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; + +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ThreadPoolManager { + private final ThreadPoolExecutor executor; + private final String successFile; + private final String failureFile; + private final AtomicInteger successCount = new AtomicInteger(0); + private final AtomicInteger failureCount = new AtomicInteger(0); + private final BlockingQueue pendingTasks = new LinkedBlockingQueue<>(); + private volatile boolean isShutdown = false; + + + + public ThreadPoolManager(int corePoolSize, int maxPoolSize, String successFile, String failureFile) { + this.successFile = successFile; + this.failureFile = failureFile; + + this.executor = new ThreadPoolExecutor( + corePoolSize, + maxPoolSize, + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(100), + new CustomRejectedExecutionHandler()); + + this.executor.allowCoreThreadTimeOut(true); + startMonitorThread(); + startPendingTaskConsumer(); + } + + public ThreadPoolManager(String successFile, String failureFile) { + this(Runtime.getRuntime().availableProcessors(), + Runtime.getRuntime().availableProcessors() * 2, + successFile, failureFile); + } + // 自定义线程工厂 + private static class CustomThreadFactory implements ThreadFactory { + private final AtomicInteger counter = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r, "pool-thread-" + counter.incrementAndGet()); + thread.setPriority(Thread.NORM_PRIORITY); + thread.setDaemon(false); + return thread; + } + } + + + // 自定义拒绝策略 + private class CustomRejectedExecutionHandler implements RejectedExecutionHandler { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + if (!isShutdown) { + // 1. 尝试直接执行(调用者线程) + try { + System.out.println("线程池饱和,由调用线程直接执行"); + r.run(); + } catch (Exception e) { + System.err.println("调用者执行任务失败: " + e.getMessage()); + } + + // 2. 记录指标 + failureCount.incrementAndGet(); + } else { + System.err.println("线程池已关闭,拒绝新任务"); + } + } + } + + + // 消费待处理任务的线程 + private void startPendingTaskConsumer() { + Thread consumerThread = new Thread(() -> { + while (!isShutdown || !pendingTasks.isEmpty()) { + try { + Runnable task = pendingTasks.take(); + // 尝试重新提交任务 + executor.submit(task); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } catch (Exception e) { + System.err.println("处理待处理任务时出错: " + e.getMessage()); + } + } + }); + consumerThread.setDaemon(true); + consumerThread.start(); + } + + + /** + * 提交文件夹处理任务(带重试机制) + */ + public void submitFolderTask(String taskName, String folderPath, + JsonProcessCallback callback, int maxRetries) { + Runnable task = () -> { + int retryCount = 0; + boolean success = false; + + while (retryCount <= maxRetries && !success && !isShutdown) { + try { + processFolder(taskName, folderPath, callback); + successCount.incrementAndGet(); + logSuccess(taskName, folderPath); + success = true; + } catch (Exception e) { + retryCount++; + if (retryCount > maxRetries) { + failureCount.incrementAndGet(); + logFailure(taskName, folderPath, + "重试" + maxRetries + "次后失败: " + e.getMessage()); + } else { + System.out.printf("[%s] 任务处理失败,第%d次重试...%n", + taskName, retryCount); + try { + Thread.sleep(1000 * retryCount); // 指数退避 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; + } + } + } + } + }; + + try { + executor.submit(task); + } catch (Exception e) { + System.err.println("提交任务失败: " + e.getMessage()); + } + } + + /** + * 批量提交文件夹处理任务 + * @param taskName 任务名称(用于日志记录) + * @param folderPaths 要处理的文件夹路径列表 + * @param callback 处理完成的回调接口 + * @return CountDownLatch 用于等待所有任务完成 + */ +// public void submitBatchFolderTasks(String taskName, List folderPaths, +// JsonProcessCallback callback, int maxRetries) { +// Semaphore semaphore = new Semaphore(executor.getMaximumPoolSize() * 2); +// +// for (String folderPath : folderPaths) { +// try { +// semaphore.acquire(); +// submitFolderTask(taskName, folderPath, callback, maxRetries); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// break; +// } finally { +// semaphore.release(); +// } +// } +// } + public void submitBatchFolderTasks(String taskName, List folderPaths, + JsonProcessCallback callback, int maxRetries) { + // 使用CountDownLatch跟踪批次完成 + CountDownLatch batchLatch = new CountDownLatch(folderPaths.size()); + + // 控制并发度的信号量 + Semaphore concurrencyLimiter = new Semaphore(executor.getMaximumPoolSize() * 2); + + for (String folderPath : folderPaths) { + try { + concurrencyLimiter.acquire(); // 获取许可 + + executor.execute(() -> { + try { + submitFolderTask(taskName, folderPath, callback, maxRetries); + } finally { + concurrencyLimiter.release(); + batchLatch.countDown(); + } + }); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + + try { + // 等待批次完成,带超时 + batchLatch.await(30, TimeUnit.MINUTES); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + private void processFolder(String taskName, String folderPath, JsonProcessCallback callback) throws IOException { + File folder = new File(folderPath); + // ... 参数校验 ... + + // 使用try-with-resources确保资源释放 + try (Stream paths = Files.list(folder.toPath())) { + paths.filter(path -> path.toString().endsWith(".txt")) + .parallel() // 并行处理文件 + .forEach(path -> { + try { + String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + JSONArray jsonArray = JSONUtil.parseArray(content); + + if (callback != null) { + callback.process(jsonArray, taskName, path.getFileName().toString()); + } + + System.out.println("[" + taskName + "] 成功处理文件: " + path); + } catch (Exception e) { + throw new RuntimeException("处理文件失败: " + path, e); + } + }); + } + } + + /** + * 记录成功处理 + */ + private synchronized void logSuccess(String taskName, String folderPath) { + Path path = Paths.get(successFile); + String record = String.format("%s | %s | %d%n", + taskName, folderPath, System.currentTimeMillis()); + try { + Files.write(path, record.getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 记录处理失败 + */ + private synchronized void logFailure(String taskName, String folderPath, String error) { + Path path = Paths.get(failureFile); + String record = String.format("%s | %s | %s | %d%n", + taskName, folderPath, error, System.currentTimeMillis()); + try { + Files.write(path, record.getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 启动监控线程 + */ + private void startMonitorThread() { + Thread monitorThread = new Thread(() -> { + while (!executor.isShutdown()) { + try { + printPoolStatus(); + checkForDeadlock(); + adjustPoolSize(); + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + }); + monitorThread.setName("pool-monitor-thread"); + monitorThread.setDaemon(true); + monitorThread.start(); + } + private void printPoolStatus() { + System.out.println("\n=== 线程池状态 ==="); + System.out.println("活跃线程: " + executor.getActiveCount()); + System.out.println("核心线程: " + executor.getCorePoolSize()); + System.out.println("最大线程: " + executor.getMaximumPoolSize()); + System.out.println("队列大小: " + executor.getQueue().size()); + System.out.println("待处理队列: " + pendingTasks.size()); + System.out.println("完成任务: " + successCount.get()); + System.out.println("失败任务: " + failureCount.get()); + System.out.println("================\n"); + } + + /** + * 检测线程池死锁情况 + */ + private void checkForDeadlock() { + // 1. 获取线程池工作线程 + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + long[] threadIds = threadMXBean.getAllThreadIds(); + + // 2. 查找死锁线程 + long[] deadlockedThreadIds = threadMXBean.findDeadlockedThreads(); + if (deadlockedThreadIds != null && deadlockedThreadIds.length > 0) { + System.err.println("⚠️ 检测到死锁线程:"); + for (long threadId : deadlockedThreadIds) { + ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId); + System.err.println("死锁线程: " + threadInfo.getThreadName()); + System.err.println("阻塞状态: " + threadInfo.getLockName() + + " 被 " + threadInfo.getLockOwnerName() + " 持有"); + + // 打印堆栈跟踪 + System.err.println("堆栈跟踪:"); + for (StackTraceElement ste : threadInfo.getStackTrace()) { + System.err.println("\t" + ste); + } + } + + // 3. 尝试恢复 - 中断死锁线程 + if (executor instanceof ThreadPoolExecutor) { + ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor; + BlockingQueue queue = tpe.getQueue(); + + System.err.println("尝试中断死锁线程并清空队列(" + queue.size() + "个任务)"); + tpe.purge(); // 清除队列中所有任务 + + // 中断所有工作线程 + for (long threadId : deadlockedThreadIds) { + ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId); + if (threadInfo != null) { + for (Thread thread : getAllThreads()) { + if (thread.getId() == threadId) { + thread.interrupt(); + System.err.println("已中断线程: " + thread.getName()); + } + } + } + } + } + } + } + + /** + * 获取JVM中所有活动线程 + */ + private List getAllThreads() { + ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); + while (rootGroup.getParent() != null) { + rootGroup = rootGroup.getParent(); + } + + Thread[] threads = new Thread[rootGroup.activeCount()]; + while (rootGroup.enumerate(threads, true) == threads.length) { + threads = new Thread[threads.length * 2]; + } + + return Arrays.stream(threads) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private void adjustPoolSize() { + // 动态调整线程池大小 + if (executor.getQueue().size() > 50 && + executor.getMaximumPoolSize() < 100) { + executor.setMaximumPoolSize(executor.getMaximumPoolSize() + 5); + } + } + /** + * 关闭线程池(优雅关闭) + */ + public void shutdown() { + isShutdown = true; + executor.shutdown(); + try { + if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + /** + * 立即关闭线程池 + */ + public void shutdownNow() { + executor.shutdownNow(); + } + + /** + * 等待所有任务完成 + */ + public void awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + executor.awaitTermination(timeout, unit); + } + + /** + * JSON处理回调接口 + */ + @FunctionalInterface + public interface JsonProcessCallback { + void process(JSONArray jsonArray, String taskName, String fileName); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/StoreDbConfigService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/StoreDbConfigService.java new file mode 100644 index 00000000..39e84951 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/StoreDbConfigService.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.sync.StoreDbConfig; +import com.suisung.mall.common.modules.sync.SyncApp; +import com.suisung.mall.common.pojo.res.ThirdApiRes; + +import java.util.List; + +public interface StoreDbConfigService extends IService { + + CommonResult findStoreDbConfigPageList(StoreDbConfig storeDbConfig, Integer pageNum, Integer pageSize); + + + StoreDbConfig getStroeConfig(StoreDbConfig storeDbConfig); + + CommonResult addStoreDbConfig(StoreDbConfig storeDbConfig); + + CommonResult updateStoreDbConfig(StoreDbConfig storeDbConfig); + + CommonResult delStoreDbConfig(StoreDbConfig storeDbConfig); + String getPrimaryKey(SyncApp syncApp); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncAppService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncAppService.java index 3351450f..e9fa1cc2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncAppService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncAppService.java @@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import com.suisung.mall.common.modules.sync.SyncApp; +import java.util.Map; + public interface SyncAppService extends IService { /** @@ -83,4 +85,13 @@ public interface SyncAppService extends IService { * @return */ SyncApp checkAppSign(String appKey, String sign, String postData); + + /** + * 获取加密的appKey,sign,streId + * @param primaryKey + * @return + */ + Map getAppSign(String primaryKey); + + boolean checkPrimaryKey(String primaryKey); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncFileLogService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncFileLogService.java new file mode 100644 index 00000000..07e3eb10 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncFileLogService.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.service; + + +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.sync.StoreDbConfig; +import com.suisung.mall.common.modules.sync.SyncFileLog; +import com.suisung.mall.common.pojo.res.ThirdApiRes; +import com.suisung.mall.core.web.service.IBaseService; + +import java.util.List; + +public interface SyncFileLogService extends IBaseService { + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java index e0bfcb1d..bb641cf4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/SyncThirdDataService.java @@ -10,9 +10,14 @@ package com.suisung.mall.shop.sync.service; import cn.hutool.json.JSONArray; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.sync.StoreDbConfig; import com.suisung.mall.common.pojo.req.SyncThirdMemberReq; import com.suisung.mall.common.pojo.res.ThirdApiRes; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.List; public interface SyncThirdDataService { @@ -54,4 +59,28 @@ public interface SyncThirdDataService { * @return */ CommonResult syncManual(String storeId, Integer syncType); + + /** + * + * @param appKey + * @param sign + * @param multipartFile + * @return + */ + ThirdApiRes fileUpload(String appKey, String sign,String path,String syncType, MultipartFile multipartFile); + + + /** + * + * @param appKey + * @param sign + * @param folders + * @return + */ + void SyncReadSxFileData(String appKey, String sign,String syncType, List folders); + + + ResponseEntity downloadToClient(String primaryKey); + + ThirdApiRes getStoreDbConfig(String appKey,String sign); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java new file mode 100644 index 00000000..7e895f9d --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.enums.DicEnum; +import com.suisung.mall.common.modules.store.ShopStoreBase; +import com.suisung.mall.common.modules.sync.StoreDbConfig; +import com.suisung.mall.common.modules.sync.SyncApp; +import com.suisung.mall.common.pojo.res.ThirdApiRes; +import com.suisung.mall.common.utils.ContextUtil; +import com.suisung.mall.common.utils.StringUtils; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.store.service.ShopStoreBaseService; +import com.suisung.mall.shop.sync.Utils.CryptoUtils; +import com.suisung.mall.shop.sync.mapper.StoreDbConfigMapper; +import com.suisung.mall.shop.sync.service.StoreDbConfigService; + +import com.suisung.mall.shop.sync.service.SyncAppService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.swing.*; +import java.util.Objects; + +import static com.suisung.mall.common.utils.ContextUtil.getStoreId; + + +@Service +public class StoreDbConfigServiceImpl extends BaseServiceImpl implements StoreDbConfigService { + + @Autowired + private ShopStoreBaseService shopStoreBaseService; + @Autowired + private SyncAppService syncAppService; + + @Override + public CommonResult findStoreDbConfigPageList(StoreDbConfig storeDbConfig,Integer pageNum,Integer pageSize) { + checked(); + String storeId= getStoreId(storeDbConfig.getStoreId()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + queryWrapper.eq("has_internet", storeDbConfig.getHasInternet()); + queryWrapper.eq("has_start", storeDbConfig.getHasInternet()); + return CommonResult.success(this.lists(queryWrapper,pageNum,pageSize)); + } + + @Override + public StoreDbConfig getStroeConfig(StoreDbConfig storeDbConfig) { + checked(); + if(ObjectUtil.isEmpty(storeDbConfig)){ + return null; + } + String storeId= getStoreId(storeDbConfig.getStoreId()); + storeDbConfig.setStoreId(storeId); + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + if(null!=storeDbConfig.getId()){ + queryWrapper.eq("id", storeDbConfig.getId()); + } + return this.getOne(queryWrapper); + } + + @Override + public CommonResult addStoreDbConfig(StoreDbConfig storeDbConfig) { + checked(); + if(ObjectUtil.isEmpty(storeDbConfig)){ + return CommonResult.failed("店铺数据库连接配置缺少必要参数"); + } + String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作 + if(StringUtils.isEmpty(storeId)){ + return CommonResult.failed("店铺数据库连接配置新增失败"); + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + if(null!=storeDbConfig.getId()){ + queryWrapper.eq("id", storeDbConfig.getId()); + } + queryWrapper.eq("has_start",DicEnum.YESORNO_1.getCode()); + if(null!=this.getOne(queryWrapper)){ + return CommonResult.failed("店铺已存在有效配置,不能重复添加"); + } + ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId)); + if(shopStoreBase==null){ + return CommonResult.failed("店铺数据库连接配置新增失败:失败原因是店铺不存在"); + } + storeDbConfig.setStoreId(storeId); + if(!this.save(storeDbConfig)){ + return CommonResult.failed("店铺数据库连接配置新增失败"); + } + return CommonResult.success(); + } + + @Override + public CommonResult updateStoreDbConfig(StoreDbConfig storeDbConfig) { + checked(); + if(ObjectUtil.isEmpty(storeDbConfig)){ + return CommonResult.failed("店铺数据库连接配置缺少必要参数"); + } + if(ObjectUtil.isEmpty(storeDbConfig.getId())){ + return CommonResult.failed("店铺数据库连接配置缺少必要参数"); + } + String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作 + ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId)); + if(shopStoreBase==null){ + return CommonResult.failed("店铺数据库连接配置新增失败:失败原因是店铺不存在"); + } + storeDbConfig.setStoreId(storeId); + if(!this.updateById(storeDbConfig)){ + return CommonResult.failed("店铺数据库连接配置更新失败"); + } + return CommonResult.success(); + } + + @Override + public CommonResult delStoreDbConfig(StoreDbConfig storeDbConfig) { + checked(); + if(ObjectUtil.isEmpty(storeDbConfig)){ + return CommonResult.failed("店铺数据库连接配置缺少必要参数"); + } + if(ObjectUtil.isEmpty(storeDbConfig.getId())){ + return CommonResult.failed("店铺数据库连接配置缺少必要参数"); + } + String storeId= getStoreId(storeDbConfig.getStoreId());//保证不能跨数据操作 + ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId)); + if(shopStoreBase==null){ + return CommonResult.failed("店铺数据库连接配置删除失败:失败原因是店铺不存在"); + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + queryWrapper.eq("id", storeDbConfig.getId()); + StoreDbConfig delDb= getOne(queryWrapper); + if(delDb==null){ + return CommonResult.failed("店铺数据库连接配置删除失败"); + } + if(!this.removeById(delDb.getId())){ + return CommonResult.failed("店铺数据库连接配置删除失败"); + } + return CommonResult.success(); + } + + + @Override + public String getPrimaryKey(SyncApp syncApp) { + checked(); + if(ObjectUtil.isEmpty(syncApp)){ + throw new RuntimeException("对象不能为空"); + } + if(ObjectUtil.isEmpty(syncApp.getStore_id())){ + throw new RuntimeException("商店编号不能为空"); + } + String storeId= getStoreId(syncApp.getStore_id());//保证不能跨数据操作 + ShopStoreBase shopStoreBase=shopStoreBaseService.get(Convert.toInt(storeId)); + if(shopStoreBase==null){ + throw new RuntimeException("商品不存在"); + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + SyncApp result= syncAppService.getOne(queryWrapper); + String primaryKey=""; + try { + primaryKey= CryptoUtils.packAndEncrypt(result.getApp_key(),result.getApp_secret(),result.getStore_id()); + } catch (Exception e) { + throw new RuntimeException(e); + } + return primaryKey; + } + + private void checked(){ + int roleId= Objects.requireNonNull(ContextUtil.getCurrentUser()).getRole_id(); + if(roleId!=9){ + throw new RuntimeException("仅为平台操作"); + } + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncAppServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncAppServiceImpl.java index e4c5bb91..fe01fa9d 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncAppServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncAppServiceImpl.java @@ -8,6 +8,7 @@ package com.suisung.mall.shop.sync.service.impl; +import cn.hutool.core.convert.Convert; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; @@ -16,19 +17,25 @@ import com.suisung.mall.common.modules.sync.SyncApp; import com.suisung.mall.common.utils.CommonUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.sync.Utils.CryptoUtils; import com.suisung.mall.shop.sync.mapper.SyncAppMapper; import com.suisung.mall.shop.sync.service.SyncAppService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; @Service +@lombok.extern.slf4j.Slf4j public class SyncAppServiceImpl extends BaseServiceImpl implements SyncAppService { @Autowired private SyncAppMapper syncAppMapper; + /** * 根据 appKey 获取一条记录 * @@ -181,4 +188,50 @@ public class SyncAppServiceImpl extends BaseServiceImpl return result; } + + @Override + public Map getAppSign(String primaryKey) { + Map resultMap=new HashMap<>(); + try { + primaryKey=CryptoUtils.dealBlankStr(primaryKey); + Map map=CryptoUtils.decryptAndUnpack(primaryKey); +// String appKey=map.get("appKey"); +// String sign=map.get("sign"); + String storeId=map.get("storeId"); + QueryWrapper queryWrapper = new QueryWrapper<>(); + SyncApp syncApp= getOne(queryWrapper.select("store_id","app_secret","app_key").eq("store_id", storeId)); + if(syncApp==null){ + return null; + } + resultMap.put("resultCode", HttpStatus.OK); + resultMap.put("primaryKey",CryptoUtils.packAndEncrypt(syncApp.getApp_key(),syncApp.getApp_secret(),syncApp.getStore_id())); + } catch (Exception e) { + log.info("解析失败:"+e.getMessage()); + resultMap.put("resultCode",500); + resultMap.put("msg:","解析失败:"+e.getMessage()); + } + return resultMap; + } + + @Override + public boolean checkPrimaryKey(String primaryKey) { + try { + primaryKey=CryptoUtils.dealBlankStr(primaryKey); + Map map=CryptoUtils.decryptAndUnpack(primaryKey); + String appKey=map.get("appKey"); + String sign=map.get("sign"); + String storeId=map.get("storeId"); + log.info("店铺:{}校验",storeId); + QueryWrapper queryWrapper = new QueryWrapper<>(); + SyncApp syncApp= getOne(queryWrapper.select("store_id","app_secret","app_key"). + eq("store_id", storeId). + eq("app_key", appKey).eq("app_secret", sign)); + if(syncApp==null){ + return false; + } + } catch (Exception e) { + return false; + } + return true; + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java new file mode 100644 index 00000000..4a32bc65 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java @@ -0,0 +1,695 @@ +package com.suisung.mall.shop.sync.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.alibaba.excel.util.DateUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.api.StateCode; +import com.suisung.mall.common.constant.CommonConstant; +import com.suisung.mall.common.exception.ApiException; +import com.suisung.mall.common.feignService.AccountService; +import com.suisung.mall.common.feignService.PayService; +import com.suisung.mall.common.modules.account.AccountUserBase; +import com.suisung.mall.common.modules.account.AccountUserInfo; +import com.suisung.mall.common.modules.base.ShopBaseProductBrand; +import com.suisung.mall.common.modules.base.ShopBaseProductCategory; +import com.suisung.mall.common.modules.base.ShopBaseProductType; +import com.suisung.mall.common.modules.number.ShopNumberSeq; +import com.suisung.mall.common.modules.pay.PayUserResource; +import com.suisung.mall.common.modules.product.*; +import com.suisung.mall.common.modules.sixun.SxSyncGoods; +import com.suisung.mall.common.modules.sixun.SxSyncVip; +import com.suisung.mall.common.modules.store.ShopStoreBase; +import com.suisung.mall.common.pojo.req.SyncThirdMemberReq; +import com.suisung.mall.common.utils.DateTimeUtils; +import com.suisung.mall.common.utils.I18nUtil; +import com.suisung.mall.common.utils.StringUtils; +import com.suisung.mall.shop.base.service.ShopBaseProductBrandService; +import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService; +import com.suisung.mall.shop.base.service.ShopBaseProductTypeService; +import com.suisung.mall.shop.number.service.impl.ShopNumberSeqServiceImpl; +import com.suisung.mall.shop.product.service.ShopProductBaseService; +import com.suisung.mall.shop.product.service.impl.ShopProductBaseServiceImpl; +import com.suisung.mall.shop.product.service.impl.ShopProductItemServiceImpl; +import com.suisung.mall.shop.sixun.dto.SxGoosModel; +import com.suisung.mall.shop.store.service.ShopStoreBaseService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.util.Pair; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +@Service +public abstract class SyncBaseThirdSxAbstract{ + private final Logger logger = LoggerFactory.getLogger(SyncBaseThirdSxAbstract.class); + @Autowired + private ShopBaseProductBrandService productBrandService; + @Autowired + private ShopBaseProductCategoryService productCategoryService; + @Autowired + private ShopBaseProductTypeService productTypeService; + @Autowired + private ShopProductBaseService shopProductBaseService; + @Autowired + private ShopStoreBaseService shopStoreBaseService; + @Autowired + private AccountService accountService; + @Autowired + private PayService payService; + @Autowired + private ShopNumberSeqServiceImpl shopNumberSeqServiceImpl; + @Autowired + private ShopProductBaseServiceImpl shopProductBaseServiceImpl; + @Autowired + private ShopProductItemServiceImpl shopProductItemServiceImpl; + + /** + * 对商品分类进行保存 + * @param list + * @param categoryListJSON + * @param storeId + * @return + */ + public int baseSaveOrUpdateShopBaseProductCategoryBatch(List list ,JSONArray categoryListJSON, + String storeId){ + int count = 0; + for (int i = 0; i < list.size(); i++) { + list.get(i).setStore_id(storeId); // app 记录传进来 + list.get(i).setData_source(2); // 思迅数据来源 + list.get(i).setCategory_is_enable(1); + + JSONObject o = (JSONObject) categoryListJSON.get(i); + if (o != null) { + // 重要:分类类型处理(强调共性) + Integer typeId = 1001; + if (StrUtil.isNotBlank(o.getStr("product_type"))) { + ShopBaseProductType productType = productTypeService.getProductTypeByName(o.getStr("product_type")); + if (productType != null) { + list.get(i).setType_id(productType.getType_id()); + } else { + // 新增一个类型 + ShopBaseProductType newProductType = new ShopBaseProductType(); + newProductType.setType_name(o.getStr("product_type")); + newProductType.setType_buildin(0); + + if (productTypeService.save(newProductType)) { + typeId = newProductType.getType_id(); + } + } + + list.get(i).setType_id(typeId); + } + + + // 处理(第一级)父类字段 产品分类 + Integer firstParentId = 0; + if (StrUtil.isNotBlank(o.getStr("first_category_name"))) { + // TODO storeId 不判断一下吗? + ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("first_category_name")); + if (cate != null) { + list.get(i).setParent_id(cate.getCategory_id()); + } else { + // 新增一个(第一级)父类 + ShopBaseProductCategory firstCate = new ShopBaseProductCategory(); + firstCate.setCategory_name(o.getStr("first_category_name")); + firstCate.setParent_id(0); + firstCate.setStore_id(storeId); + firstCate.setType_id(typeId); + firstCate.setData_source(2); + if (productCategoryService.saveOrUpdate(firstCate)) { + // 当前子分类的父类id + firstParentId = firstCate.getId(); + list.get(i).setParent_id(firstParentId); + } + } + + list.get(i).setParent_id(firstParentId); + } + + // 处理(第二级)父类字段 产品分类 + if (StrUtil.isNotBlank(o.getStr("second_category_name"))) { + // TODO storeId 不判断一下吗? + ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("second_category_name")); + if (cate != null) { + list.get(i).setParent_id(cate.getCategory_id()); + } else { + // 新增一个(第二级)父类 + ShopBaseProductCategory secondCate = new ShopBaseProductCategory(); + secondCate.setCategory_name(o.getStr("second_category_name")); + secondCate.setParent_id(firstParentId); + secondCate.setStore_id(storeId); + secondCate.setType_id(typeId); + secondCate.setData_source(2); + if (productCategoryService.saveOrUpdate(secondCate)) { + // 当前子分类的第二级父类id + list.get(i).setParent_id(secondCate.getId()); + } + } + } + + } + + ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getParent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id()); + if (productCategoryTemp != null) { + // 更改记录 + if (!productCategoryTemp.getCategory_image().equals(list.get(i).getCategory_image()) + || !productCategoryTemp.getType_id().equals(list.get(i).getType_id()) + || !productCategoryTemp.getCategory_virtual_enable().equals(list.get(i).getCategory_virtual_enable()) + || !productCategoryTemp.getCategory_commission_rate().equals(list.get(i).getCategory_commission_rate()) + || !productCategoryTemp.getCategory_show_type().equals(list.get(i).getCategory_show_type())) { + list.get(i).setCategory_id(productCategoryTemp.getCategory_id()); + } else { + continue; + } + } + + if (productCategoryService.saveOrUpdate(list.get(i))) { + count++; + } + } + + return count; + } + + /** + * 保存品牌 + * @param goodBrandList + * @param storeId + * @param brandListJSON + * @return + */ + public int baseSaveOrUpdateShopBaseProductBrandBatch(List goodBrandList,String storeId,JSONArray brandListJSON){ + int count = 0; + for (int i = 0; i < goodBrandList.size(); i++) { + goodBrandList.get(i).setStore_id(Integer.valueOf(storeId)); // app 记录传进来 + JSONObject o = (JSONObject) brandListJSON.get(i); + if (o != null && StrUtil.isNotBlank(o.getStr("category"))) { + // category 一般是父分类名 + ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("category")); + if (cate != null) { + goodBrandList.get(i).setCategory_id(cate.getCategory_id()); + } else { + // TODO 如果没有分类,是否新建? + } + } + + count += productBrandService.saveOrUpdateBrand2(goodBrandList.get(i)); + } + + return count; + } + + /** + * 保存商品 + * @param goodsListJSON + * @param storeId + * @return + */ + public int baseSaveOrUpdateGoods(JSONArray goodsListJSON,String storeId){ + int count = 0; + Map categoryMap= productCategoryService.getCategoryListByStoreId(storeId);//热数据加载 + for (JSONObject jsonObj : goodsListJSON.jsonIter()) { + Date currentDate = new Date(); + String cateGoryId=""; + if(null!=categoryMap.get(jsonObj.get("first_category_name"))){ + cateGoryId=categoryMap.get(jsonObj.get("first_category_name")).toString(); + } + Integer categoryId = Convert.toInt(cateGoryId, 0); + Integer storeIdInt = Convert.toInt(storeId); + ShopStoreBase store_row = shopStoreBaseService.get(storeId); + if (store_row == null) { + throw new ApiException(I18nUtil._("无法获取店铺信息!")); + } + + ShopProductBase shopProductBase = new ShopProductBase(); + shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟 + shopProductBase.setStore_id(storeIdInt); + + shopProductBase.setProduct_number((String) jsonObj.get("product_number")); + shopProductBase.setProduct_name((String) jsonObj.get("product_name")); + shopProductBase.setStore_name(store_row.getStore_name()); + shopProductBase.setProduct_tips(""); + shopProductBase.setProduct_video(""); + shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY); + shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定; + shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 + shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销 + shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅; + shopProductBase.setProduct_add_time(currentDate.getTime()); + + // ShopProductIndex + ShopProductIndex shopProductIndex = new ShopProductIndex(); + shopProductIndex.setProduct_add_time(currentDate.getTime()); + shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟 + shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT) + shopProductIndex.setProduct_tags("");// 商品标签(DOT) + shopProductIndex.setBrand_id(0); + shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用 + shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT) + shopProductIndex.setCategory_id(categoryId); // 商品分类 + shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 + shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销 + shopProductIndex.setStore_id(storeIdInt); + shopProductIndex.setStore_type(store_row.getStore_type()); + shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品 + shopProductIndex.setStore_is_open(store_row.getStore_is_open()); + shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport()); + shopProductIndex.setStore_longitude(store_row.getStore_longitude()); + shopProductIndex.setStore_latitude(store_row.getStore_latitude()); + + shopProductIndex.setCard_type_id(0); + shopProductIndex.setVoucher_activity_id(""); + shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT) + shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY)); + + ShopBaseProductCategory category_row = productCategoryService.get(categoryId); + if (ObjectUtil.isNotEmpty(category_row)) { + Integer type_id = category_row.getType_id(); + shopProductIndex.setType_id(type_id); + } + + // shop_product_data + ShopProductData shopProductData = new ShopProductData(); + // product_id // 产品id + shopProductData.setProduct_edit_time(currentDate); + + // shop_product_detail + ShopProductDetail shopProductDetail = new ShopProductDetail(); + shopProductDetail.setProduct_detail(""); + shopProductDetail.setProduct_param(""); + shopProductDetail.setProduct_service(""); + shopProductDetail.setProduct_tags(""); + + // shop_product_info + ShopProductInfo shopProductInfo = new ShopProductInfo(); + shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号 + shopProductInfo.setProduct_assist(""); + shopProductInfo.setProduct_spec(""); + + shopProductInfo.setProduct_buy_limit(0); // 不限购 + //商品规格 + shopProductInfo.setSpec_ids(""); + + List shopProductItemList = new ArrayList<>(); + ShopProductItem shopProductItem = new ShopProductItem(); + shopProductItem.setStore_id(storeIdInt); + shopProductItem.setCategory_id(categoryId); + //零售价 + shopProductItem.setItem_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + shopProductItem.setItem_advice_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + shopProductItem.setItem_market_price(BigDecimal.valueOf(jsonObj.getDouble("original_price"))); + //积分价 + shopProductItem.setItem_unit_points(new BigDecimal(jsonObj.getInt("points"))); + shopProductItem.setItem_quantity(jsonObj.getInt("stock")); // 库存 + shopProductItem.setItem_quantity_frozen(0); + shopProductItem.setItem_number(jsonObj.getStr("product_number"));// SKU商家编码 + shopProductItem.setItem_barcode(jsonObj.getStr("product_number")); // 条形码正常情况下就是货号 + shopProductItem.setItem_is_default(1); + shopProductItem.setItem_enable(1); + + shopProductItemList.add(shopProductItem); + + // 保存数据 + Pair pair = shopProductBaseService.saveProduct(shopProductBase, shopProductIndex, shopProductData, shopProductDetail, shopProductInfo, shopProductItemList, new ArrayList(), new ShopProductValidPeriod(), new ArrayList()); + if (!pair.getFirst()) { + logger.error(pair.getSecond()); + continue; + } + + count += 1; + } + return count; + } + + /** + * 保存会员 + * @param memberList + * @param storeId + * @return + */ + public int baseSaveOrUpdateMemberBatch(List memberList,String storeId){ + int count = 0; + for (SyncThirdMemberReq member : memberList) { + // account_user_base + AccountUserBase accountUserBase = new AccountUserBase(); + accountUserBase.setUser_account(StringUtils.generateUniqueCode(8)); + accountUserBase.setUser_nickname(member.getUser_nickname()); + accountUserBase.setUser_state(2);// 状态(ENUM):0-锁定;1-未激活;2-已激活; + accountUserBase.setUser_is_admin(CommonConstant.USER_TYPE_NORMAL); + accountUserBase.setStore_ids(storeId); + accountUserBase.setRights_group_id("0");// 普通用户,不是商家 + accountUserBase.setUser_type(CommonConstant.USER_TYPE_NORMAL); + + // 默认给了随机密码和盐,token + String user_key = IdUtil.simpleUUID(); + String user_salt = IdUtil.simpleUUID(); + String user_token = IdUtil.simpleUUID(); + accountUserBase.setUser_salt(user_salt); + accountUserBase.setUser_token(user_token); + accountUserBase.setUser_key(user_key); + accountUserBase.setUser_password(SecureUtil.md5(user_salt + SecureUtil.md5(IdUtil.simpleUUID()))); + + // 判断店铺是不是存在该昵称的会员了? + Boolean exists = accountService.existByNickname(member.getUser_nickname(), storeId); + if (exists) { + continue; + } + + AccountUserBase accountUserBase2 = accountService.saveOrUpdateUserBase2(accountUserBase); + + // 新增用户记录后,返回 userId ? + Integer userId = accountUserBase2.getUser_id(); + if (userId == null || userId <= 0) { + continue; + } + + // account_user_info + AccountUserInfo accountUserInfo = new AccountUserInfo(); + accountUserInfo.setUser_id(userId); + accountUserInfo.setUser_type_id(0); + accountUserInfo.setUser_mobile(member.getUser_mobile()); + accountUserInfo.setUser_level_card(member.getUser_level_card()); + //user_level_id + accountUserInfo.setUser_level_id(1); // todo select id + accountUserInfo.setUser_gender(member.getUser_gender()); + accountUserInfo.setUser_mobile(member.getUser_mobile()); + accountUserInfo.setUser_intl(CommonConstant.IDD_ZH_CN); + accountUserInfo.setUser_birthday(DateTimeUtils.parseDate(member.getUser_birthday(), "yyyy-MM-dd")); + boolean success = accountService.saveOrUpdateUserInfo(accountUserInfo); + if (member.getUser_money() != null || member.getUser_points() != null) { + // pay_user_resource 用户支付资源,积分,余额 + PayUserResource payUserResource = new PayUserResource(); + payUserResource.setUser_id(userId); + payUserResource.setUser_money(member.getUser_money()); + payUserResource.setUser_money_frozen(BigDecimal.ZERO); + payUserResource.setUser_points(member.getUser_points()); + payUserResource.setUser_points_frozen(BigDecimal.ZERO); + success = payService.saveOrUpdatePayUserResource(payUserResource); + } + + if (success) { + count += 1; + } + } + return count; + } + + /** + * List 转换为 List + * @param sxSyncVipList + * @return + */ + public List ConverList(List sxSyncVipList){ + List syncThirdMemberReqList=new ArrayList<>(); + if(CollUtil.isNotEmpty(sxSyncVipList)){ + SyncThirdMemberReq syncThirdMemberReq=null; + for (SxSyncVip sxSyncVip : sxSyncVipList) { + syncThirdMemberReq = new SyncThirdMemberReq(); + syncThirdMemberReq.setUser_nickname(sxSyncVip.getVip_name()); + syncThirdMemberReq.setUser_realname(sxSyncVip.getVip_name()); + if (sxSyncVip.getVip_name().equals("男")) {//todo 需要确认数据是不是这样判断 + syncThirdMemberReq.setUser_gender(1); + } + if (sxSyncVip.getVip_name().equals("女")) { + syncThirdMemberReq.setUser_gender(2); + } + syncThirdMemberReq.setUser_mobile(sxSyncVip.getMobile()); + syncThirdMemberReq.setUser_birthday(sxSyncVip.getBirthday()); + syncThirdMemberReq.setUser_level(sxSyncVip.getCard_type());//todo 涉及会员等级字典转换 + syncThirdMemberReq.setUser_level_card(sxSyncVip.getCard_no()); + syncThirdMemberReq.setUser_points(sxSyncVip.getNow_acc_num()); + syncThirdMemberReq.setUser_money(sxSyncVip.getResidual_amt()); + if(sxSyncVip.getVip_date()!=null){ + try { + syncThirdMemberReq.setJoin_time(DateUtils.parseDate(sxSyncVip.getVip_date())); + } catch (ParseException e) { + logger.info("时间转换异常{0}",e); + throw new RuntimeException(e); + } + } + + } + } + return syncThirdMemberReqList; + } + + /** + * 将List转换为List + * @param sxSyncGoods + * @return + */ + public List CvtToGoosModel(List sxSyncGoods){ + if(CollectionUtil.isEmpty(sxSyncGoods)){ + return null; + } + List sxGoosModelList=new ArrayList<>(); + SxGoosModel sxGoosModel=null; + for (SxSyncGoods sxSyncGood:sxSyncGoods){ + sxGoosModel=new SxGoosModel(); + sxGoosModel.setProduct_name(sxSyncGood.getItem_subname()); + sxGoosModel.setProduct_number("");// todo + sxGoosModel.setProduct_barcode("");// todo + sxGoosModel.setFirst_category_name("");// todo + sxGoosModel.setSecond_category_name("");// todo + sxGoosModel.setThree_category_name("");// todo + sxGoosModel.setProduct_type("");// todo + sxGoosModel.setProduct_kind("");// todo + sxGoosModel.setCost_price(sxSyncGood.getPrice());//成本价 todo + sxGoosModel.setOriginal_price(sxSyncGood.getSale_price());//原价 todo + sxGoosModel.setOriginal_price(sxSyncGood.getSale_price());//零售价=原价? + sxGoosModel.setMember_price(sxSyncGood.getVip_price());//会员价 + sxGoosModel.setStock(sxSyncGood.getStock());//库存 todo + sxGoosModel.setGross_margin(sxSyncGood.getGross_margin()); //毛利率 todo + sxGoosModel.setUnit(sxSyncGood.getUnit_no());//单位 + sxGoosModel.setCan_piont(new BigDecimal(0));//可用积分 todo + sxGoosModel.setPoints(sxSyncGood.getVip_acc_num());//总积分 todo + sxGoosModel.setMnemonic(sxSyncGood.getItem_rem());//助记码 todo + sxGoosModel.setBuy_limit(0);//最大购买商品量 todo + sxGoosModel.setBrand_name("");//品牌 todo + sxGoosModel.setTags("");//标签 todo + + sxGoosModel.setProduct_assist(Arrays.asList("时令果蔬","生鲜"));//帮助 todo + + sxGoosModel.setProduct_spec(Collections.singletonList(sxSyncGood.getItem_size()));//规格 + + sxGoosModel.setProduct_value("");//商品卖点特征 todo + + sxGoosModel.setProduct_video("");//商品视频 todo + + sxGoosModel.setProduct_desc("");//商品描述 todo + + sxGoosModel.setProduct_images(new ArrayList<>());//介绍图片 todo + + sxGoosModel.setPromotion_detail(new ArrayList<>());//活动列表 todo + + sxGoosModelList.add(sxGoosModel); + } + return sxGoosModelList; + } + + + /** + * 批量保存商品 + * @param goodsListJSON + * @param storeId + * @return + */ + public int baseSaveOrUpdateGoodsBatch(JSONArray goodsListJSON,String storeId){ + AtomicInteger resultCount = new AtomicInteger(); + Map categoryMap= productCategoryService.getCategoryListByStoreId(storeId);//热数据加载 + List shopProductBaseList=new ArrayList<>(); + List shopProductIndexList=new ArrayList<>(); ; + List shopProductDataList=new ArrayList<>(); ; + List shopProductDetailList=new ArrayList<>(); ; + List shopProductInfoList=new ArrayList<>(); ; + List> shopProductItemLists=new ArrayList<>(); + ShopStoreBase store_row = shopStoreBaseService.get(storeId); + if (store_row == null) { + throw new ApiException(I18nUtil._("无法获取店铺信息!")); + } + goodsListJSON.stream().parallel().forEach(object -> { + final JSONObject jsonObj= (JSONObject) object; + Date currentDate = new Date(); + String cateGoryId=""; + if(null!=categoryMap.get(jsonObj.get("first_category_name"))){ + cateGoryId=categoryMap.get(jsonObj.get("first_category_name")).toString(); + } + Integer categoryId = Convert.toInt(cateGoryId, 0); + Integer storeIdInt = Convert.toInt(storeId); + + + ShopProductBase shopProductBase = new ShopProductBase(); + shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟 + shopProductBase.setStore_id(storeIdInt); + + shopProductBase.setProduct_number((String) jsonObj.get("product_number")); + shopProductBase.setProduct_name((String) jsonObj.get("product_name")); + shopProductBase.setStore_name(store_row.getStore_name()); + shopProductBase.setProduct_tips(""); + shopProductBase.setProduct_video(""); + shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY); + shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定; + shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 + shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销 + shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅; + shopProductBase.setProduct_add_time(currentDate.getTime()); + + // ShopProductIndex + ShopProductIndex shopProductIndex = new ShopProductIndex(); + shopProductIndex.setProduct_add_time(currentDate.getTime()); + shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟 + shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT) + shopProductIndex.setProduct_tags("");// 商品标签(DOT) + shopProductIndex.setBrand_id(0); + shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用 + shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT) + shopProductIndex.setCategory_id(categoryId); // 商品分类 + shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 + shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销 + shopProductIndex.setStore_id(storeIdInt); + shopProductIndex.setStore_type(store_row.getStore_type()); + shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品 + shopProductIndex.setStore_is_open(store_row.getStore_is_open()); + shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport()); + shopProductIndex.setStore_longitude(store_row.getStore_longitude()); + shopProductIndex.setStore_latitude(store_row.getStore_latitude()); + + shopProductIndex.setCard_type_id(0); + shopProductIndex.setVoucher_activity_id(""); + shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT) + shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY)); + + ShopBaseProductCategory category_row = productCategoryService.get(categoryId); + if (ObjectUtil.isNotEmpty(category_row)) { + Integer type_id = category_row.getType_id(); + shopProductIndex.setType_id(type_id); + } + + // shop_product_data + ShopProductData shopProductData = new ShopProductData(); + // product_id // 产品id + shopProductData.setProduct_edit_time(currentDate); + + // shop_product_detail + ShopProductDetail shopProductDetail = new ShopProductDetail(); + shopProductDetail.setProduct_detail(""); + shopProductDetail.setProduct_param(""); + shopProductDetail.setProduct_service(""); + shopProductDetail.setProduct_tags(""); + + // shop_product_info + ShopProductInfo shopProductInfo = new ShopProductInfo(); + shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号 + shopProductInfo.setProduct_assist(""); + shopProductInfo.setProduct_spec(""); + + shopProductInfo.setProduct_buy_limit(0); // 不限购 + //商品规格 + shopProductInfo.setSpec_ids(""); + + List shopProductItemList = new ArrayList<>(); + ShopProductItem shopProductItem = new ShopProductItem(); + shopProductItem.setStore_id(storeIdInt); + shopProductItem.setCategory_id(categoryId); + //零售价 + shopProductItem.setItem_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + shopProductItem.setItem_advice_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + shopProductItem.setItem_market_price(BigDecimal.valueOf(jsonObj.getDouble("original_price"))); + //积分价 + shopProductItem.setItem_unit_points(new BigDecimal(jsonObj.getInt("points"))); + shopProductItem.setItem_quantity(jsonObj.getInt("stock")); // 库存 + shopProductItem.setItem_quantity_frozen(0); + shopProductItem.setItem_number(jsonObj.getStr("product_number"));// SKU商家编码 + shopProductItem.setItem_barcode(jsonObj.getStr("product_number")); // 条形码正常情况下就是货号 + shopProductItem.setItem_is_default(1); + shopProductItem.setItem_enable(1); + + //添加数据到list + synchronized(shopProductBaseList){ + shopProductItemList.add(shopProductItem); + shopProductBaseList.add(shopProductBase); + shopProductIndexList.add(shopProductIndex); + shopProductDataList.add(shopProductData); + shopProductDetailList.add(shopProductDetail); + shopProductInfoList.add(shopProductInfo); + shopProductItemLists.add(shopProductItemList); + } +// synchronized(shopProductIndexList){ +// shopProductIndexList.add(shopProductIndex); +// } +// +// synchronized(shopProductDataList){ +// shopProductDataList.add(shopProductData); +// } +// +// synchronized(shopProductDetailList){ +// shopProductDetailList.add(shopProductDetail); +// } +// +// synchronized(shopProductInfoList){ +// shopProductInfoList.add(shopProductInfo); +// } +// +// synchronized(shopProductItemLists){ +// shopProductItemLists.add(shopProductItemList); +// } + + // 保存数据 + + resultCount.addAndGet(1); + }); + shopProductBaseService.saveProductBatch(shopProductBaseList,shopProductIndexList,shopProductDataList,shopProductDetailList,shopProductInfoList,shopProductItemLists, + new ArrayList>(), + new ArrayList(), + new ArrayList()); + + return resultCount.get(); + } + + + public void syncPrimaryKey(){ + + List shopNumberSeqList=new ArrayList<>(); + QueryWrapper baseWrapper=new QueryWrapper<>(); + baseWrapper.select("MAX(product_id) as product_id"); + ShopProductBase shopProductBase= shopProductBaseServiceImpl.getOne(baseWrapper); + Long productId= shopProductBase.getProduct_id()+1; + //QueryWrapper baseSeWrapper=new QueryWrapper(); + //baseSeWrapper.eq("prefix", "product_id"); + ShopNumberSeq shopNumberSeqBase= new ShopNumberSeq(); + shopNumberSeqBase.setPrefix("product_id"); + shopNumberSeqBase.setNumber(productId); + //shopNumberSeqServiceImpl.edit(shopNumberSeqBase,baseWrapper); + //查询产品item + QueryWrapper itemQuery=new QueryWrapper<>(); + itemQuery.select("MAX(item_id) as item_id"); + ShopProductItem shopProductItem= shopProductItemServiceImpl.getOne(itemQuery); + Long itemtId= shopProductItem.getItem_id()+1; + // QueryWrapper itemWrapper=new QueryWrapper(); + //itemWrapper.eq("prefix", "item_id"); + ShopNumberSeq shopNumberSeqItem= new ShopNumberSeq(); + shopNumberSeqItem.setNumber(itemtId); + shopNumberSeqItem.setPrefix("item_id"); + shopNumberSeqList.add(shopNumberSeqBase); + shopNumberSeqList.add(shopNumberSeqItem); + shopNumberSeqServiceImpl.batchUpdateSeq(shopNumberSeqList); + shopNumberSeqServiceImpl.clearRelateGoodsId(); + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncConfigServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncConfigServiceImpl.java index f4d0bff0..09937aa2 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncConfigServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncConfigServiceImpl.java @@ -8,4 +8,6 @@ import org.springframework.stereotype.Service; @Service public class SyncConfigServiceImpl extends ServiceImpl implements SyncConfigService { + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncFileLogServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncFileLogServiceImpl.java new file mode 100644 index 00000000..53645adf --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncFileLogServiceImpl.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.service.impl; +import com.suisung.mall.common.modules.sync.SyncFileLog; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.sync.mapper.SyncFileLogMapper; + +import com.suisung.mall.shop.sync.service.SyncFileLogService; +import org.springframework.stereotype.Service; + + + +@Service +public class SyncFileLogServiceImpl extends BaseServiceImpl implements SyncFileLogService { + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java index d9f3fded..08fb43bc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java @@ -9,79 +9,120 @@ package com.suisung.mall.shop.sync.service.impl; import cn.hutool.core.collection.CollUtil; + +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.SecureUtil; +import cn.hutool.http.HttpException; import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONObject; + import cn.hutool.json.JSONUtil; + import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.api.CommonResult; -import com.suisung.mall.common.api.StateCode; -import com.suisung.mall.common.constant.CommonConstant; -import com.suisung.mall.common.exception.ApiException; -import com.suisung.mall.common.feignService.AccountService; -import com.suisung.mall.common.feignService.PayService; -import com.suisung.mall.common.modules.account.AccountUserBase; -import com.suisung.mall.common.modules.account.AccountUserInfo; + +import com.suisung.mall.common.domain.UserDto; +import com.suisung.mall.common.enums.DicEnum; import com.suisung.mall.common.modules.base.ShopBaseProductBrand; import com.suisung.mall.common.modules.base.ShopBaseProductCategory; -import com.suisung.mall.common.modules.base.ShopBaseProductType; -import com.suisung.mall.common.modules.pay.PayUserResource; -import com.suisung.mall.common.modules.product.*; -import com.suisung.mall.common.modules.store.ShopStoreBase; + +import com.suisung.mall.common.modules.sixun.SxSyncGoods; +import com.suisung.mall.common.modules.sixun.SxSyncVip; +import com.suisung.mall.common.modules.sync.StoreDbConfig; import com.suisung.mall.common.modules.sync.SyncApp; import com.suisung.mall.common.modules.sync.SyncConfig; +import com.suisung.mall.common.modules.sync.SyncFileLog; import com.suisung.mall.common.pojo.req.SyncThirdMemberReq; import com.suisung.mall.common.pojo.res.ThirdApiRes; -import com.suisung.mall.common.utils.DateTimeUtils; + +import com.suisung.mall.common.utils.ContextUtil; import com.suisung.mall.common.utils.I18nUtil; + import com.suisung.mall.common.utils.StringUtils; -import com.suisung.mall.shop.base.service.ShopBaseProductBrandService; -import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService; -import com.suisung.mall.shop.base.service.ShopBaseProductTypeService; -import com.suisung.mall.shop.product.service.ShopProductBaseService; -import com.suisung.mall.shop.product.service.impl.ShopProductBaseServiceImpl; -import com.suisung.mall.shop.store.service.ShopStoreBaseService; -import com.suisung.mall.shop.sync.service.SyncAppService; -import com.suisung.mall.shop.sync.service.SyncConfigService; -import com.suisung.mall.shop.sync.service.SyncThirdDataService; +import com.suisung.mall.core.web.service.RedisService; +import com.suisung.mall.shop.number.service.ShopNumberSeqService; +import com.suisung.mall.shop.page.service.OssService; +import com.suisung.mall.shop.sixun.dao.SxDataDao; +import com.suisung.mall.shop.sixun.dto.DataBaseInfo; +import com.suisung.mall.shop.sixun.dto.SxCategoryModel; +import com.suisung.mall.shop.sixun.dto.SxGoosModel; +import com.suisung.mall.shop.sixun.service.SxSyncCategoryService; +import com.suisung.mall.shop.sixun.service.SxSyncGoodsService; +import com.suisung.mall.shop.sixun.service.SxSyncVipService; +import com.suisung.mall.shop.sixun.utils.CommonUtil; +import com.suisung.mall.shop.sixun.utils.FileUtils; +import com.suisung.mall.shop.sync.Utils.CryptoUtils; +import com.suisung.mall.shop.sync.Utils.ThreadFileUtils; +import com.suisung.mall.shop.sync.keymanage.RedisKey; +import com.suisung.mall.shop.sync.service.*; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.util.Pair; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DriverManagerDataSource; -import org.springframework.stereotype.Service; -import java.math.BigDecimal; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + + @Service -public class SyncThirdDataServiceImpl implements SyncThirdDataService { - private final Logger logger = LoggerFactory.getLogger(ShopProductBaseServiceImpl.class); +public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements SyncThirdDataService { + private static Logger logger = LoggerFactory.getLogger(SyncThirdDataServiceImpl.class); private final int limitCnt = 300; - @Autowired - private ShopBaseProductBrandService productBrandService; - @Autowired - private ShopBaseProductCategoryService productCategoryService; - @Autowired - private ShopBaseProductTypeService productTypeService; - @Autowired - private AccountService accountService; - @Autowired - private PayService payService; - @Autowired - private ShopProductBaseService shopProductBaseService; - @Autowired - private ShopStoreBaseService shopStoreBaseService; + @Value("${client.path}") + public String clientPath; @Autowired private SyncAppService syncAppService; @Autowired private SyncConfigService syncConfigService; + @Autowired + private SxSyncCategoryService sxSyncCategoryService; + + @Autowired + private SxSyncGoodsService sxSyncGoodsService; + + @Autowired + private SxSyncVipService sxSyncVipService; + @Autowired + private ShopNumberSeqService shopNumberSeqService; + private final AtomicLong threadNum=new AtomicLong(0); + @Autowired + private SyncFileLogService syncFileLogService; + @Autowired + private OssService ossService; + + @Autowired + private RedisService redisService; + + @Autowired + private StoreDbConfigService storeDbConfigService; + + private final static String CLIENTFILEPATH="sxclient/"; + + /** * 批量保存商品的分类 @@ -111,103 +152,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!")); } - int count = 0; - for (int i = 0; i < list.size(); i++) { - list.get(i).setStore_id(storeId); // app 记录传进来 - list.get(i).setData_source(2); // 思迅数据来源 - list.get(i).setCategory_is_enable(1); - - JSONObject o = (JSONObject) categoryListJSON.get(i); - if (o != null) { - - // 重要:分类类型处理(强调共性) - Integer typeId = 1001; - if (StrUtil.isNotBlank(o.getStr("product_type"))) { - ShopBaseProductType productType = productTypeService.getProductTypeByName(o.getStr("product_type")); - if (productType != null) { - list.get(i).setType_id(productType.getType_id()); - } else { - // 新增一个类型 - ShopBaseProductType newProductType = new ShopBaseProductType(); - newProductType.setType_name(o.getStr("product_type")); - newProductType.setType_buildin(0); - - if (productTypeService.save(newProductType)) { - typeId = newProductType.getType_id(); - } - } - - list.get(i).setType_id(typeId); - } - - - // 处理(第一级)父类字段 产品分类 - Integer firstParentId = 0; - if (StrUtil.isNotBlank(o.getStr("first_category_name"))) { - // TODO storeId 不判断一下吗? - ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("first_category_name")); - if (cate != null) { - list.get(i).setParent_id(cate.getCategory_id()); - } else { - // 新增一个(第一级)父类 - ShopBaseProductCategory firstCate = new ShopBaseProductCategory(); - firstCate.setCategory_name(o.getStr("first_category_name")); - firstCate.setParent_id(0); - firstCate.setStore_id(storeId); - firstCate.setType_id(typeId); - firstCate.setData_source(2); - if (productCategoryService.saveOrUpdate(firstCate)) { - // 当前子分类的父类id - firstParentId = firstCate.getId(); - list.get(i).setParent_id(firstParentId); - } - } - - list.get(i).setParent_id(firstParentId); - } - - // 处理(第二级)父类字段 产品分类 - if (StrUtil.isNotBlank(o.getStr("second_category_name"))) { - // TODO storeId 不判断一下吗? - ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("second_category_name")); - if (cate != null) { - list.get(i).setParent_id(cate.getCategory_id()); - } else { - // 新增一个(第二级)父类 - ShopBaseProductCategory secondCate = new ShopBaseProductCategory(); - secondCate.setCategory_name(o.getStr("second_category_name")); - secondCate.setParent_id(firstParentId); - secondCate.setStore_id(storeId); - secondCate.setType_id(typeId); - secondCate.setData_source(2); - if (productCategoryService.saveOrUpdate(secondCate)) { - // 当前子分类的第二级父类id - list.get(i).setParent_id(secondCate.getId()); - } - } - } - - } - - ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getParent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id()); - if (productCategoryTemp != null) { - // 更改记录 - if (!productCategoryTemp.getCategory_image().equals(list.get(i).getCategory_image()) - || !productCategoryTemp.getType_id().equals(list.get(i).getType_id()) - || !productCategoryTemp.getCategory_virtual_enable().equals(list.get(i).getCategory_virtual_enable()) - || !productCategoryTemp.getCategory_commission_rate().equals(list.get(i).getCategory_commission_rate()) - || !productCategoryTemp.getCategory_show_type().equals(list.get(i).getCategory_show_type())) { - list.get(i).setCategory_id(productCategoryTemp.getCategory_id()); - } else { - continue; - } - } - - if (productCategoryService.saveOrUpdate(list.get(i))) { - count++; - } - } - + int count=baseSaveOrUpdateShopBaseProductCategoryBatch(list,categoryListJSON,storeId); Map resp = new HashMap<>(); resp.put("count", count); @@ -242,23 +187,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!")); } - int count = 0; - for (int i = 0; i < goodBrandList.size(); i++) { - goodBrandList.get(i).setStore_id(Integer.valueOf(storeId)); // app 记录传进来 - JSONObject o = (JSONObject) brandListJSON.get(i); - if (o != null && StrUtil.isNotBlank(o.getStr("category"))) { - // category 一般是父分类名 - ShopBaseProductCategory cate = productCategoryService.getCategoryByName(o.getStr("category")); - if (cate != null) { - goodBrandList.get(i).setCategory_id(cate.getCategory_id()); - } else { - // TODO 如果没有分类,是否新建? - } - } - - count += productBrandService.saveOrUpdateBrand2(goodBrandList.get(i)); - } - + int count=baseSaveOrUpdateShopBaseProductBrandBatch(goodBrandList,storeId,brandListJSON); Map resp = new HashMap<>(); resp.put("count", count); @@ -276,7 +205,6 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) || ObjectUtil.isEmpty(goodsListJSON)) { return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!")); } - // 验签、appid,必要参数判断 SyncApp syncApp = syncAppService.checkAppSign(appKey, sign, goodsListJSON.toString()); if (syncApp == null) { @@ -288,115 +216,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!")); } - - int count = 0; - for (JSONObject jsonObj : goodsListJSON.jsonIter()) { - Date currentDate = new Date(); - - Integer categoryId = Convert.toInt(jsonObj.get("first_category_name"), 0); - Integer storeIdInt = Convert.toInt(storeId); - ShopStoreBase store_row = shopStoreBaseService.get(storeId); - if (store_row == null) { - throw new ApiException(I18nUtil._("无法获取店铺信息!")); - } - - ShopProductBase shopProductBase = new ShopProductBase(); - shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟 - shopProductBase.setStore_id(storeIdInt); - shopProductBase.setProduct_number((String) jsonObj.get("product_number")); - shopProductBase.setProduct_name((String) jsonObj.get("product_name")); - shopProductBase.setStore_name(store_row.getStore_name()); - shopProductBase.setProduct_tips(""); - shopProductBase.setProduct_video(""); - shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY); - shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); - shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定; - shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 - shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销 - shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅; - shopProductBase.setProduct_add_time(currentDate.getTime()); - - // ShopProductIndex - ShopProductIndex shopProductIndex = new ShopProductIndex(); - shopProductIndex.setProduct_add_time(currentDate.getTime()); - shopProductIndex.setProduct_sale_time(DateUtil.current() + 600); //10分钟 - shopProductIndex.setStore_category_ids(""); // 店铺分类编号(DOT) - shopProductIndex.setProduct_tags("");// 商品标签(DOT) - shopProductIndex.setBrand_id(0); - shopProductIndex.setProduct_name(shopProductBase.getProduct_name()); // 产品名称:店铺平台先在对用表中检索后通过id检索,检索使用 - shopProductIndex.setProduct_name_index(shopProductIndex.getProduct_name()); // 名称索引关键字(DOT) - shopProductIndex.setCategory_id(categoryId); // 商品分类 - shopProductIndex.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 - shopProductIndex.setProduct_dist_enable(0); // 是否允许三级分销 - shopProductIndex.setStore_id(storeIdInt); - shopProductIndex.setStore_type(store_row.getStore_type()); - shopProductIndex.setKind_id(StateCode.PRODUCT_KIND_ENTITY);// 实体商品 - shopProductIndex.setStore_is_open(store_row.getStore_is_open()); - shopProductIndex.setStore_is_selfsupport(store_row.getStore_is_selfsupport()); - shopProductIndex.setStore_longitude(store_row.getStore_longitude()); - shopProductIndex.setStore_latitude(store_row.getStore_latitude()); - - shopProductIndex.setCard_type_id(0); - shopProductIndex.setVoucher_activity_id(""); - shopProductIndex.setCoupon_type_id(0);// product_assist_data // 辅助属性值列(DOT) - shopProductIndex.setProduct_transport_id(String.valueOf(StateCode.DELIVERY_TYPE_SAME_CITY)); - - ShopBaseProductCategory category_row = productCategoryService.get(categoryId); - if (ObjectUtil.isNotEmpty(category_row)) { - Integer type_id = category_row.getType_id(); - shopProductIndex.setType_id(type_id); - } - - // shop_product_data - ShopProductData shopProductData = new ShopProductData(); - // product_id // 产品id - shopProductData.setProduct_edit_time(currentDate); - - // shop_product_detail - ShopProductDetail shopProductDetail = new ShopProductDetail(); - shopProductDetail.setProduct_detail(""); - shopProductDetail.setProduct_param(""); - shopProductDetail.setProduct_service(""); - shopProductDetail.setProduct_tags(""); - - // shop_product_info - ShopProductInfo shopProductInfo = new ShopProductInfo(); - shopProductInfo.setProduct_number((String) jsonObj.get("product_number"));// SPU商家编码:货号 - shopProductInfo.setProduct_assist(""); - shopProductInfo.setProduct_spec(""); - shopProductInfo.setProduct_buy_limit(0); // 不限购 - //商品规格 - shopProductInfo.setSpec_ids(""); - - List shopProductItemList = new ArrayList<>(); - ShopProductItem shopProductItem = new ShopProductItem(); - shopProductItem.setStore_id(storeIdInt); - shopProductItem.setCategory_id(categoryId); - //零售价 - shopProductItem.setItem_unit_price((BigDecimal) jsonObj.get("retail_price")); - shopProductItem.setItem_advice_price((BigDecimal) jsonObj.get("retail_price")); - shopProductItem.setItem_market_price((BigDecimal) jsonObj.get("retail_price")); - //积分价 - shopProductItem.setItem_unit_points((BigDecimal) jsonObj.get("points")); - shopProductItem.setItem_quantity((Integer) jsonObj.get("stock")); // 库存 - shopProductItem.setItem_quantity_frozen(0); - shopProductItem.setItem_number((String) jsonObj.get("product_number"));// SKU商家编码 - shopProductItem.setItem_barcode((String) jsonObj.get("product_number")); // 条形码正常情况下就是货号 - shopProductItem.setItem_is_default(1); - shopProductItem.setItem_enable(1); - - shopProductItemList.add(shopProductItem); - - // 保存数据 - Pair pair = shopProductBaseService.saveProduct(shopProductBase, shopProductIndex, shopProductData, shopProductDetail, shopProductInfo, shopProductItemList, new ArrayList(), new ShopProductValidPeriod(), new ArrayList()); - if (!pair.getFirst()) { - logger.error(pair.getSecond()); - continue; - } - - count += 1; - } - + int count=baseSaveOrUpdateGoods(goodsListJSON,storeId); Map resp = new HashMap<>(); resp.put("count", count); @@ -426,72 +246,7 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { return new ThirdApiRes().fail(1004, I18nUtil._("单次同步记录最多" + limitCnt + "条!")); } - int count = 0; - for (SyncThirdMemberReq member : memberList) { - // account_user_base - AccountUserBase accountUserBase = new AccountUserBase(); - accountUserBase.setUser_account(StringUtils.generateUniqueCode(8)); - accountUserBase.setUser_nickname(member.getUser_nickname()); - accountUserBase.setUser_state(2);// 状态(ENUM):0-锁定;1-未激活;2-已激活; - accountUserBase.setUser_is_admin(CommonConstant.USER_TYPE_NORMAL); - accountUserBase.setStore_ids(storeId); - accountUserBase.setRights_group_id("0");// 普通用户,不是商家 - accountUserBase.setUser_type(CommonConstant.USER_TYPE_NORMAL); - - // 默认给了随机密码和盐,token - String user_key = IdUtil.simpleUUID(); - String user_salt = IdUtil.simpleUUID(); - String user_token = IdUtil.simpleUUID(); - accountUserBase.setUser_salt(user_salt); - accountUserBase.setUser_token(user_token); - accountUserBase.setUser_key(user_key); - accountUserBase.setUser_password(SecureUtil.md5(user_salt + SecureUtil.md5(IdUtil.simpleUUID()))); - - // 判断店铺是不是存在该昵称的会员了? - Boolean exists = accountService.existByNickname(member.getUser_nickname(), storeId); - if (exists) { - continue; - } - - AccountUserBase accountUserBase2 = accountService.saveOrUpdateUserBase2(accountUserBase); - - // 新增用户记录后,返回 userId ? - Integer userId = accountUserBase2.getUser_id(); - if (userId == null || userId <= 0) { - continue; - } - - // account_user_info - AccountUserInfo accountUserInfo = new AccountUserInfo(); - accountUserInfo.setUser_id(userId); - accountUserInfo.setUser_type_id(0); - accountUserInfo.setUser_mobile(member.getUser_mobile()); - accountUserInfo.setUser_level_card(member.getUser_level_card()); - //user_level_id - accountUserInfo.setUser_level_id(1); // todo select id - accountUserInfo.setUser_gender(member.getUser_gender()); - accountUserInfo.setUser_mobile(member.getUser_mobile()); - accountUserInfo.setUser_intl(CommonConstant.IDD_ZH_CN); - accountUserInfo.setUser_birthday(DateTimeUtils.parseDate(member.getUser_birthday(), "yyyy-MM-dd")); - boolean success = accountService.saveOrUpdateUserInfo(accountUserInfo); - - if (member.getUser_money() != null || member.getUser_points() != null) { - // pay_user_resource 用户支付资源,积分,余额 - PayUserResource payUserResource = new PayUserResource(); - payUserResource.setUser_id(userId); - payUserResource.setUser_money(member.getUser_money()); - payUserResource.setUser_money_frozen(BigDecimal.ZERO); - payUserResource.setUser_points(member.getUser_points()); - payUserResource.setUser_points_frozen(BigDecimal.ZERO); - - success = payService.saveOrUpdatePayUserResource(payUserResource); - } - - if (success) { - count += 1; - } - } - + int count =baseSaveOrUpdateMemberBatch(memberList,storeId); Map resp = new HashMap<>(); resp.put("count", count); @@ -530,42 +285,18 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { return CommonResult.failed(); } - //jdbcTemplate - JdbcTemplate jdbcTemplate = getJDBCTemplate(syncConfig); - if (null == jdbcTemplate) { - return CommonResult.failed(); - } - //1-品牌,2-分类,3-商品,4-会员 switch (syncType) { case 1: - return syncProductBrand(jdbcTemplate); + return syncProductBrand(new DataBaseInfo(),storeId);//todo case 2: - return syncProductClazz(jdbcTemplate); + return syncProductClazz(new DataBaseInfo(),storeId);//todo 测试 case 3: - return syncProduct(jdbcTemplate); + return syncProduct(new DataBaseInfo(),storeId);//todo 没做完 case 4: - return syncVip(jdbcTemplate); + return syncVip(new DataBaseInfo(),storeId);//todo 测试 } - return null; - } - - //创建Template - private JdbcTemplate getJDBCTemplate(SyncConfig syncConfig) { - - switch (syncConfig.getSys_version()) { - case "hbposev9": - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - String url = String.format("jdbc:sqlserver://%s:%s;databaseName=%s", - syncConfig.getSever_ip(), syncConfig.getSql_port(), syncConfig.getSql_db()); - dataSource.setUrl(url); - dataSource.setUsername(syncConfig.getSql_acc()); - dataSource.setPassword(syncConfig.getSql_pwd()); - // 创建 JdbcTemplate - return new JdbcTemplate(dataSource); - } - return null; + return CommonResult.success(); } @@ -574,13 +305,27 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { * * @return */ - public CommonResult syncProduct(JdbcTemplate template) { - //商品编码 item_no、商品名称 item_name、零售价 sale_price、会员价 vip_price - String sql = "SELECT item_no, item_name, sale_price, vip_price FROM t_bd_item_info"; - - List oList = template.queryForList(sql, String.class); - //todo 第三方 商品同步接口 - return null; + public CommonResult syncProduct(DataBaseInfo dataBaseInfo,String storeId) { + int total= sxSyncGoodsService.getGoodsTotal(dataBaseInfo); + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + int syncCount =0; + for (int i = 1; i < pages; i++) { + int count=0; + List sxSyncGoodsList= sxSyncGoodsService.findGoodsListPage(dataBaseInfo,i,pages); + //todo 数据转换 + List sxGoosModelList= CvtToGoosModel(sxSyncGoodsList); + if(CollectionUtil.isEmpty(sxSyncGoodsList)){ + continue; + } + count= baseSaveOrUpdateGoods(JSONUtil.parseArray(sxGoosModelList),storeId); + if(count<=0){ + continue; + } + syncCount+=count; + } + logger.info("同步商品的总数为{},成功数量为{}",total,syncCount); + return CommonResult.success(); } @@ -589,12 +334,30 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { * * @return */ - public CommonResult syncVip(JdbcTemplate template) { - //会员卡号card_no、card_id、会员姓名vip_name、手机号vip_tel | mobile、性别 vip_sex、生日 birthday - String sql = "SELECT card_no, card_id, vip_name, vip_tel, vip_sex, birthday FROM t_rm_vip_info"; - List oList = template.queryForList(sql, String.class); - //todo 第三方 会员同步接口 - return null; + public CommonResult syncVip(DataBaseInfo dataBaseInfo,String storeId) { + // 记录总数 + Integer total = sxSyncVipService.getVipMembersTotal(dataBaseInfo); + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + List memberList=new ArrayList<>(); + SyncThirdMemberReq syncThirdMemberReq=null; + int syncCount =0; + for (int i = 1; i < pages; i++) { + memberList.clear(); + int count = 0; + syncThirdMemberReq=new SyncThirdMemberReq(); + List sxSyncVipList= sxSyncVipService.findVipMemberPage(dataBaseInfo,i,SxDataDao.PAGESIZE); + //处理数据转换SxSyncVip>SyncThirdMemberReq + memberList=ConverList(sxSyncVipList); + memberList.add(syncThirdMemberReq); + count=baseSaveOrUpdateMemberBatch(memberList,storeId); + if (count <= 0) { + continue; + } + syncCount+=count; + } + logger.info("vip会员总共有{}条数据,同步完成{}条",total,syncCount); + return CommonResult.success(); } /** @@ -602,17 +365,287 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService { * * @return */ - public CommonResult syncProductBrand(JdbcTemplate template) { + public CommonResult syncProductBrand(DataBaseInfo dataBaseInfo,String storeId) { return null; } /** * 同步商品分类 - * * @return */ - public CommonResult syncProductClazz(JdbcTemplate template) { - return null; + public CommonResult syncProductClazz(DataBaseInfo dataBaseInfo,String storeId) { + // 记录总数 + Integer total = sxSyncCategoryService.getCategoryTotal(dataBaseInfo); + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + int syncCount =0; + for (int i = 1; i <= pages; i++) { + int count = 0; + List list = sxSyncCategoryService.getCategoryByDataBasePage(dataBaseInfo,i,SxDataDao.PAGESIZE); + if (CollUtil.isEmpty(list)) { + continue; + } + JSONArray categoryListJSON=JSONUtil.parseArray(list); + List shopBaseProductCategories = JSONUtil.toList(categoryListJSON, ShopBaseProductCategory.class); + if (shopBaseProductCategories == null) { + logger.info("转换类型为空,类方法为{}","com.suisung.mall.shop.sync.service.impl.SyncThirdDataServiceImpl.syncProductClazz"); + continue; + } + count = baseSaveOrUpdateShopBaseProductCategoryBatch(shopBaseProductCategories,categoryListJSON,storeId); + if (count <= 0) { + continue; + } + syncCount+=count; + } + logger.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount); + return CommonResult.success(); + } + + /** + * 文件上传 + * @param appKey + * @param sign + * @param page 分页 + * @param syncType + * @param multipartFile + * @return + */ + @Override + public ThirdApiRes fileUpload(String appKey, String sign,String page,String syncType, MultipartFile multipartFile) { + if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) ) { + return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!")); + } + // 验签、appid,必要参数判断 + SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper() + .select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id) + .eq(SyncApp::getApp_key, appKey) + .eq(SyncApp::getApp_secret,sign)); + if (syncAppO == null) { + return new ThirdApiRes().fail(1001, I18nUtil._("签名有误!")); + } + String storeId = syncAppO.getStore_id(); + try { + if (multipartFile.isEmpty()) { + return new ThirdApiRes().fail(1001, I18nUtil._("文件不能为空!")); + } + byte[] bytes = multipartFile.getBytes(); + String folder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+page+FileUtils.pathSeparator; + String filName=multipartFile.getOriginalFilename(); + String filePath= FileUtils.createFolderAndFileUsingFile(folder,filName); + Path path = Paths.get(filePath); + Files.write(path, bytes); +// String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath() +// .path("/download/") +// .path(Objects.requireNonNull(multipartFile.getOriginalFilename())) +// .toUriString(); + return new ThirdApiRes().success("文件上传成功"); + } catch (IOException e) { + return new ThirdApiRes().fail(500,"文件上传失败"); + } + } + + /** + * 多线程处理文件 + * @param appKey + * @param sign + * @param syncType + * @param folders + */ + @Override + public void SyncReadSxFileData(String appKey, String sign, String syncType, List folders) { + SyncApp syncApp = syncAppService.getOne(new LambdaQueryWrapper() + .select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id) + .eq(SyncApp::getApp_key, appKey) + .eq(SyncApp::getApp_secret,sign)); + String storeId = syncApp.getStore_id(); + if(null==syncApp.getStore_id()|| syncApp.getStore_id().isEmpty()){ + logger.info("商品id为空"); + return; + } + if(folders==null||folders.isEmpty()){ + logger.info("没有商品数据"); + return; + } + List newFolders=new ArrayList<>(); + folders.forEach(page->{ + String newfolder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+page+FileUtils.pathSeparator; + newFolders.add(newfolder); + }); + syncPrimaryKey(); + shopNumberSeqService.clearKey(); + ExecutorService executor = Executors.newFixedThreadPool(6); + List> futures = new ArrayList<>(); + // 提交任务 + AtomicInteger success= new AtomicInteger(); + AtomicInteger fails= new AtomicInteger(); + List failFolders=new ArrayList<>(); + List failMessage=new ArrayList<>(); + for (int i = 0; i < newFolders.size(); i++) { + final int taskId = i; + threadNum.incrementAndGet(); + futures.add(executor.submit(() -> { + int count = 0;//失败重试机制,当失败重试一次,再次失败则记录到数据库中 + while (true){ + count++; + String taskName=newFolders.get(taskId); + String fileName="good_"+taskId+".txt"; + JSONArray jsonArray=new ThreadFileUtils().processFolder(taskName,newFolders.get(taskId)); + try { + baseSaveOrUpdateGoodsBatch(jsonArray,storeId); + success.getAndIncrement(); + threadNum.decrementAndGet(); + return "成功" + taskId; + }catch (Exception e){ + if(count<2){ + continue; + } + fails.getAndIncrement(); + failFolders.add(newFolders.get(taskId)+fileName); + failMessage.add(taskId+"_"+e.getMessage()); + return "失败"+newFolders.get(taskId); + } + } + })); + } + // 等待所有任务完成 + for (Future future : futures) { + try { + System.out.println("任务结果: " + future.get()); + } catch (Exception e) { + System.err.println("任务执行异常: " + e.getMessage()); + } + } + executor.shutdown(); + //记录到数据库 + syncPrimaryKey(); + shopNumberSeqService.clearKey(); + List syncFileLogs=new ArrayList<>(); + for (int i = 0; i < failFolders.size(); i++) { + String path=failFolders.get(i); + String taskId=failMessage.get(i).split("_")[0]; + SyncFileLog syncFileLog=new SyncFileLog(); + syncFileLog.setSyncType(syncType); + syncFileLog.setFileName(path.substring(path.lastIndexOf(FileUtils.pathSeparator)+1)); + syncFileLog.setSyncStatus(DicEnum.FAILED.getCode()); + syncFileLog.setSyncTaskId(taskId); + syncFileLog.setSyncStoreId(storeId); + syncFileLog.setFilePath(path); + syncFileLog.setErrorMessage(failMessage.get(i)); + syncFileLog.setSourceSystem(DicEnum.SOURCE_SYSTEM_TYPE_1005.getCode()); + syncFileLog.setTargetSystem(DicEnum.SOURCE_SYSTEM_TYPE_SELF.getCode()); + syncFileLogs.add(syncFileLog); + } + if(CollUtil.isNotEmpty(syncFileLogs)){ + syncFileLogService.saveBatch(syncFileLogs,syncFileLogs.size()); + } + //todo 定时清理文件,建议用服务器脚本 + logger.info("执行成功{}个文件,失败{}个文件",success,fails); + logger.info("同步商品数据执行结束"); + } + + @Override + public ResponseEntity downloadToClient(String primaryKey) { + logger.info("primaryKey:{}",primaryKey); + boolean checked= syncAppService.checkPrimaryKey(primaryKey); + // UserDto userDto=ContextUtil.getCurrentUser(); + //redisService.del(RedisKey.SXCLIENTKEYVERSION);//todo 删除 + String version= (String) redisService.get(RedisKey.SXCLIENTKEYVERSION); + if(checked){ + String tempFilePath=System.getProperty("user.home"); + String clientJarPath=""; + if(StringUtils.isEmpty(version)){ + version="v1"; + //String ossFolder="/sxclient/"+version; + redisService.set(RedisKey.SXCLIENTKEYVERSION,version); + logger.error("没有版本更新"); + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=error.txt") + .header("error","noVersion") + .body(new ByteArrayResource(version.getBytes(StandardCharsets.UTF_8))); + }else { + List folderList= ossService.listFolders(CLIENTFILEPATH); + version= String.valueOf(Convert.toInt(version.split("v")[1])+1); + version="v"+version; + String finalVersion =CLIENTFILEPATH + version+"/"; + String folder= folderList.stream().filter(finalVersion::equals).collect(Collectors.joining()); + if(StringUtils.isNotEmpty(folder)){ + //String ossFolder="/sxclient/"+folder; + String filePath= ossService.listDocuments(folder).get(0).getKey(); + clientJarPath= ossService.download(filePath,tempFilePath+FileUtils.pathSeparator+filePath); + }else { + logger.error("查找没有版本更新"); + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=error.txt") + .header("error","noVersion") + .body(new ByteArrayResource(version.getBytes(StandardCharsets.UTF_8))); + } + } + if(StringUtils.isNotEmpty(clientJarPath)){ + // 构建文件路径 + Path filePath = Paths.get(clientJarPath); + File file = filePath.toFile(); + // 检查文件是否存在 + if (!file.exists()) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .header("error" ,"noFile") + .body(new ByteArrayResource(version.getBytes())); + } + // 创建Resource对象 + Resource resource = new FileSystemResource(file); + + // 获取文件MIME类型 + String contentType = null; + try { + contentType = Files.probeContentType(filePath); + } catch (IOException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .header("error" ,"500") + .body(new ByteArrayResource(version.getBytes())); + } + if (contentType == null) { + contentType = "application/octet-stream"; + } + redisService.set(RedisKey.SXCLIENTKEYVERSION,version); + // 构建响应 + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(contentType)) + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=\"" + file.getName() + "\"") + .body(resource); + } + } + logger.info("!校验失败"); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .header("error" ,"noValid") + .body(new ByteArrayResource("version".getBytes())); + } + + @Override + public ThirdApiRes getStoreDbConfig(String appKey,String sign) { + if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) ) { + return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!")); + } + // 验签、appid,必要参数判断 + SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper() + .select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id) + .eq(SyncApp::getApp_key, appKey) + .eq(SyncApp::getApp_secret,sign)); + if (syncAppO == null) { + return new ThirdApiRes().fail(1001, I18nUtil._("签名有误!")); + } + String storeId = syncAppO.getStore_id(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id", storeId); + queryWrapper.eq("has_start",DicEnum.YESORNO_1.getCode()); + StoreDbConfig storeDbConfig= storeDbConfigService.getOne(queryWrapper); + if (storeDbConfig == null) { + return new ThirdApiRes().fail(1003, I18nUtil._("服务器配置缺少配置信息!")); + } + return new ThirdApiRes().success("成功",storeDbConfig); } } diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index 1358c1bf..fb7aab8d 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -8,7 +8,7 @@ spring: mvc: static-path-pattern: /shop/static/** datasource: - url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull + url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull username: @mysql.user@ password: @mysql.pwd@ driver-class-name: @mysql.driver@ diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index f79745fd..cc07f8a6 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -8,7 +8,7 @@ spring: mvc: static-path-pattern: /shop/static/** datasource: - url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull + url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull username: @mysql.user@ password: @mysql.pwd@ driver-class-name: @mysql.driver@ @@ -181,4 +181,7 @@ esign: app_id: 7439053575 app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7 app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB - debug: true \ No newline at end of file + debug: true +#客户端上传文件地址 +client: + path: @client.path@ diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 841800e5..4750e715 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -6,7 +6,7 @@ spring: mvc: static-path-pattern: /shop/static/** datasource: - url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&maxReconnects=5 + url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&maxReconnects=5 username: @mysql.user@ password: @mysql.pwd@ driver-class-name: @mysql.driver@ diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 96dbafd4..73384e68 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -6,7 +6,7 @@ spring: mvc: static-path-pattern: /shop/static/** datasource: - url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull + url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull username: @mysql.user@ password: @mysql.pwd@ driver-class-name: @mysql.driver@ diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 96dbafd4..73384e68 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -6,7 +6,7 @@ spring: mvc: static-path-pattern: /shop/static/** datasource: - url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull + url: jdbc:mysql://@mysql.host@:@mysql.port@/@mysql.db@?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull username: @mysql.user@ password: @mysql.pwd@ driver-class-name: @mysql.driver@ diff --git a/mall-shop/src/main/resources/mapper/number/ShopNumberSeqMapper.xml b/mall-shop/src/main/resources/mapper/number/ShopNumberSeqMapper.xml index b353b471..bfedffa4 100644 --- a/mall-shop/src/main/resources/mapper/number/ShopNumberSeqMapper.xml +++ b/mall-shop/src/main/resources/mapper/number/ShopNumberSeqMapper.xml @@ -6,5 +6,32 @@ prefix, number + + + + + + + + + + + UPDATE shop_number_seq + SET + prefix = #{prefix}, + number = #{number} + WHERE prefix = #{prefix} + + + +
diff --git a/sql/shop/dev/20250520_ddl.sql b/sql/shop/dev/20250520_ddl.sql new file mode 100644 index 00000000..be3b7129 --- /dev/null +++ b/sql/shop/dev/20250520_ddl.sql @@ -0,0 +1,51 @@ +CREATE TABLE `sync_file_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `sync_task_id` varchar(64) NOT NULL COMMENT '同步任务ID', + `sync_store_id` varchar(64) NOT NULL COMMENT '店铺id', + `file_path` varchar(1024) NOT NULL COMMENT '文件路径', + `file_name` varchar(255) NOT NULL COMMENT '文件名', + `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)', + `file_md5` varchar(32) DEFAULT NULL COMMENT '文件MD5值', + `source_system` varchar(64) NOT NULL COMMENT '源系统标识', + `target_system` varchar(64) NOT NULL COMMENT '目标系统标识', + `sync_type` char(1) NOT NULL COMMENT '同步类型(1:商品,2:商品分类,3:会员,4.品牌)', + `sync_status` char(1) NOT NULL COMMENT '同步状态(0:等待中,1:进行中,2:成功,3:失败)', + `retry_count` tinyint(4) DEFAULT '0' COMMENT '重试次数', + `error_message` text , + `start_time` datetime DEFAULT NULL COMMENT '开始时间', + `end_time` datetime DEFAULT NULL COMMENT '结束时间', + `duration` int(11) DEFAULT NULL COMMENT '耗时(毫秒)', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `extra_info` json DEFAULT NULL COMMENT '额外信息(JSON格式)', + PRIMARY KEY (`id`), + KEY `idx_sync_task_id` (`sync_task_id`), + KEY `idx_file_path` (`file_path`(255)), + KEY `idx_file_name` (`file_name`), + KEY `idx_source_target` (`source_system`, `target_system`), + KEY `idx_sync_status` (`sync_status`), + KEY `idx_create_time` (`create_time`), + KEY `idx_update_time` (`update_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件同步日志表'; + +CREATE TABLE `store_db_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `store_id` varchar(64) NOT NULL COMMENT '店铺ID', + `db_type` varchar(20) NOT NULL DEFAULT 'sqlserver' COMMENT '数据库类型(mysql/oracle/sqlserver等)', + `db_name` varchar(64) NOT NULL COMMENT '数据库名称', + `db_ip` varchar(64) NOT NULL COMMENT '数据库IP地址', + `db_port` int(11) NOT NULL DEFAULT 3306 COMMENT '数据库端口', + `db_username` varchar(64) NOT NULL COMMENT '数据库用户名', + `db_password` varchar(256) NOT NULL COMMENT '数据库密码(建议加密存储)', + `has_internet` char(1) NOT NULL DEFAULT 0 COMMENT '是否有外网访问(0:无,1:有)', + `sync_mode` char(1) NOT NULL DEFAULT 2 COMMENT '同步模式(1:定时同步,2:间隔同步)', + `has_start` char(1) NOT NULL DEFAULT 1 COMMENT '是否启用(0:否,1:是)', + `cron_expression` varchar(64) DEFAULT NULL COMMENT '定时同步的cron表达式', + `category_name` text NULL DEFAULT NULL COMMENT '商品分类', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `remark` varchar(512) DEFAULT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `idx_store_id` (`store_id`), + KEY `idx_has_internet` (`has_internet`), + KEY `idx_has_start` (`has_start`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='店铺数据库连接配置表'; From db25392dbb47422fafbfad5c69d78e35c3b06ff6 Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Tue, 20 May 2025 17:56:01 +0800 Subject: [PATCH 35/39] =?UTF-8?q?=E5=95=86=E7=91=9E9.7=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/pom.xml | 126 ++++ client/readme.txt | 21 + .../com/small/client/Cache/CommonCache.java | 48 ++ .../com/small/client/ClientApplication.java | 27 + .../client/Schedule/DynamicTaskScheduler.java | 103 +++ .../com/small/client/Utils/CommonUtil.java | 98 +++ .../com/small/client/Utils/CryptoUtils.java | 110 +++ .../com/small/client/Utils/FileUtils.java | 176 +++++ .../com/small/client/Utils/HttpUtils.java | 107 +++ .../com/small/client/Utils/JarPathUtil.java | 70 ++ .../com/small/client/comment/DicEnum.java | 30 + .../com/small/client/comment/UrlComment.java | 11 + .../com/small/client/config/ClientConfig.java | 14 + .../com/small/client/config/TaskConfig.java | 18 + .../client/controller/WebController.java | 79 +++ .../java/com/small/client/dao/BaseDao.java | 246 +++++++ .../java/com/small/client/dao/SxDataDao.java | 448 ++++++++++++ .../java/com/small/client/dto/BrandModel.java | 27 + .../com/small/client/dto/CommentModel.java | 17 + .../com/small/client/dto/DataBaseInfo.java | 33 + .../com/small/client/dto/ImBranchStock.java | 18 + .../com/small/client/dto/ProductImage.java | 17 + .../com/small/client/dto/PromotionDetail.java | 17 + .../java/com/small/client/dto/ResultDto.java | 15 + .../com/small/client/dto/SpecPriceDto.java | 19 + .../com/small/client/dto/StoreDbConfig.java | 64 ++ .../com/small/client/dto/SxCategoryModel.java | 32 + .../com/small/client/dto/SxGoosModel.java | 103 +++ .../com/small/client/dto/SxSyncCategory.java | 68 ++ .../com/small/client/dto/SxSyncGoods.java | 118 ++++ .../java/com/small/client/dto/SxSyncVip.java | 80 +++ .../client/dto/SyncGoodsSearchModel.java | 22 + .../small/client/dto/SyncThirdMemberReq.java | 54 ++ .../com/small/client/dto/UploadModel.java | 15 + .../java/com/small/client/enums/DicEnum.java | 72 ++ .../service/SxDataAbst/SxDataAbstService.java | 180 +++++ .../small/client/service/SxDataService.java | 53 ++ .../client/service/WebClientService.java | 88 +++ .../client/service/imp/SxDataServiceImp.java | 645 ++++++++++++++++++ client/src/main/resources/application.yml | 15 + client/src/main/resources/logback.xml | 19 + 41 files changed, 3523 insertions(+) create mode 100644 client/pom.xml create mode 100644 client/readme.txt create mode 100644 client/src/main/java/com/small/client/Cache/CommonCache.java create mode 100644 client/src/main/java/com/small/client/ClientApplication.java create mode 100644 client/src/main/java/com/small/client/Schedule/DynamicTaskScheduler.java create mode 100644 client/src/main/java/com/small/client/Utils/CommonUtil.java create mode 100644 client/src/main/java/com/small/client/Utils/CryptoUtils.java create mode 100644 client/src/main/java/com/small/client/Utils/FileUtils.java create mode 100644 client/src/main/java/com/small/client/Utils/HttpUtils.java create mode 100644 client/src/main/java/com/small/client/Utils/JarPathUtil.java create mode 100644 client/src/main/java/com/small/client/comment/DicEnum.java create mode 100644 client/src/main/java/com/small/client/comment/UrlComment.java create mode 100644 client/src/main/java/com/small/client/config/ClientConfig.java create mode 100644 client/src/main/java/com/small/client/config/TaskConfig.java create mode 100644 client/src/main/java/com/small/client/controller/WebController.java create mode 100644 client/src/main/java/com/small/client/dao/BaseDao.java create mode 100644 client/src/main/java/com/small/client/dao/SxDataDao.java create mode 100644 client/src/main/java/com/small/client/dto/BrandModel.java create mode 100644 client/src/main/java/com/small/client/dto/CommentModel.java create mode 100644 client/src/main/java/com/small/client/dto/DataBaseInfo.java create mode 100644 client/src/main/java/com/small/client/dto/ImBranchStock.java create mode 100644 client/src/main/java/com/small/client/dto/ProductImage.java create mode 100644 client/src/main/java/com/small/client/dto/PromotionDetail.java create mode 100644 client/src/main/java/com/small/client/dto/ResultDto.java create mode 100644 client/src/main/java/com/small/client/dto/SpecPriceDto.java create mode 100644 client/src/main/java/com/small/client/dto/StoreDbConfig.java create mode 100644 client/src/main/java/com/small/client/dto/SxCategoryModel.java create mode 100644 client/src/main/java/com/small/client/dto/SxGoosModel.java create mode 100644 client/src/main/java/com/small/client/dto/SxSyncCategory.java create mode 100644 client/src/main/java/com/small/client/dto/SxSyncGoods.java create mode 100644 client/src/main/java/com/small/client/dto/SxSyncVip.java create mode 100644 client/src/main/java/com/small/client/dto/SyncGoodsSearchModel.java create mode 100644 client/src/main/java/com/small/client/dto/SyncThirdMemberReq.java create mode 100644 client/src/main/java/com/small/client/dto/UploadModel.java create mode 100644 client/src/main/java/com/small/client/enums/DicEnum.java create mode 100644 client/src/main/java/com/small/client/service/SxDataAbst/SxDataAbstService.java create mode 100644 client/src/main/java/com/small/client/service/SxDataService.java create mode 100644 client/src/main/java/com/small/client/service/WebClientService.java create mode 100644 client/src/main/java/com/small/client/service/imp/SxDataServiceImp.java create mode 100644 client/src/main/resources/application.yml create mode 100644 client/src/main/resources/logback.xml diff --git a/client/pom.xml b/client/pom.xml new file mode 100644 index 00000000..8c99599a --- /dev/null +++ b/client/pom.xml @@ -0,0 +1,126 @@ + + + 4.0.0 + + com.small + client + v1 + jar + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + + + UTF-8 + UTF-8 + 8 + 8 + 5.8.20 + + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.commons + commons-text + 1.10.0 + + + org.projectlombok + lombok + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + com.microsoft.sqlserver + mssql-jdbc + 9.4.1.jre8 + + + ch.qos.logback + logback-classic + + + + cn.hutool + hutool-all + ${hutool.version} + + + + + + + + ali-maven + https://maven.aliyun.com/repository/central + + true + + + true + always + fail + + + + repo.maven.apache.org + https://repo.maven.apache.org/maven2 + + true + + + true + always + fail + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + repackage + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + \ No newline at end of file diff --git a/client/readme.txt b/client/readme.txt new file mode 100644 index 00000000..7bcd7ded --- /dev/null +++ b/client/readme.txt @@ -0,0 +1,21 @@ +本系统主要安装在客户端 +主要有以下几个功能 + +第一阶段 +1、通过http获取远程数据小发服务配置,基础数据包括主要包括数据库地址ip,数据库名称,数据库密码,以及同步定时时间 + +2.采集本地数据库,通过多线程调用同步接口,同步商品,种类,会员 + +第二阶段 +由于系统的数据同步存在性能瓶颈,需要使用文件传输的方式同步数据, +文件采用分页形式同步数据,每一页使用一个文件,服务器解析文件采用多线程解析方式解析 + + + +打包功能更,需要写一个shell脚本自动打包放到服务器供给下载和java的jkd安装包,这些下载放到后端的网页端,暴露下载地址 + +todo +1、通过http获取dataInfo没有写 +2、文件传输没有写 +3.商品同步没有写 +4.商品分类同步没有写 diff --git a/client/src/main/java/com/small/client/Cache/CommonCache.java b/client/src/main/java/com/small/client/Cache/CommonCache.java new file mode 100644 index 00000000..d90da612 --- /dev/null +++ b/client/src/main/java/com/small/client/Cache/CommonCache.java @@ -0,0 +1,48 @@ +package com.small.client.Cache; + +import cn.hutool.cache.Cache; +import cn.hutool.cache.impl.FIFOCache; +import cn.hutool.core.date.DateUnit; +import com.small.client.dto.BrandModel; +import com.small.client.dto.SpecPriceDto; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 用于本地缓存 + */ +@Component +public class CommonCache { + public final static String CACHE_CATEGROY = "CACHE_CATEGROY";//分类缓存 + + private Cache cache =new FIFOCache<>(20000); + + private Cache> spriceCache =new FIFOCache<>(20); + + private Cache> brandCahce =new FIFOCache<>(20); + + public void put(String key, String value) { + cache.put(key, value, DateUnit.MINUTE.getMillis()*20); + } + + public String get(String key) { + return cache.get(key); + } + + public void putSpecPrice(String key, List value) { + spriceCache.put(key, value, DateUnit.MINUTE.getMillis()*20); + } + + public List getSpecPrice(String key) { + return spriceCache.get(key); + } + + public List getBrandCahce(String key) { + return brandCahce.get(key); + } + + public void setBrandCahce(String key, List value) { + brandCahce.put(key, value, DateUnit.MINUTE.getMillis()*20); + } +} diff --git a/client/src/main/java/com/small/client/ClientApplication.java b/client/src/main/java/com/small/client/ClientApplication.java new file mode 100644 index 00000000..1a61fead --- /dev/null +++ b/client/src/main/java/com/small/client/ClientApplication.java @@ -0,0 +1,27 @@ +package com.small.client; + +import com.small.client.Utils.JarPathUtil; +import com.small.client.service.SxDataService; +import com.small.client.service.WebClientService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +import javax.annotation.Resource; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +@SpringBootApplication +@Slf4j +public class ClientApplication{ + public static void main(String[] args) { + SpringApplication.run(ClientApplication.class, args); + } + +} \ No newline at end of file diff --git a/client/src/main/java/com/small/client/Schedule/DynamicTaskScheduler.java b/client/src/main/java/com/small/client/Schedule/DynamicTaskScheduler.java new file mode 100644 index 00000000..56d0c47c --- /dev/null +++ b/client/src/main/java/com/small/client/Schedule/DynamicTaskScheduler.java @@ -0,0 +1,103 @@ +package com.small.client.Schedule; + +import com.small.client.dto.CommentModel; +import com.small.client.dto.DataBaseInfo; +import com.small.client.service.SxDataService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; + +@Service +@Slf4j +public class DynamicTaskScheduler { + private final TaskScheduler taskScheduler; + private final SxDataService sxDataService; + private final Map> scheduledTasks = new ConcurrentHashMap<>(); + + private boolean isRuning =false; + + @Autowired + public DynamicTaskScheduler(TaskScheduler taskScheduler, SxDataService sxDataService) { + this.taskScheduler = taskScheduler; + this.sxDataService = sxDataService; + } + + @PostConstruct + public void initTasks() { + refreshTasks(); + // 每5分钟检查一次数据库更新 + taskScheduler.scheduleAtFixedRate(this::refreshTasks, Duration.ofHours(1)); + } + + public void refreshTasks() { + if(!isRuning){ + sxDataService.checkForUpdates();//检查app更新 + } + CommentModel commentModel =sxDataService.getCommentModel(); + DataBaseInfo enabledTask = sxDataService.getDataBaseInfo(commentModel); + + List enabledTasks=new ArrayList<>(); + enabledTasks.add(enabledTask); + // 移除已禁用或删除的任务 + scheduledTasks.keySet().removeIf(taskKey -> + enabledTasks.stream().noneMatch(task -> task.getDataBaseName().equals(taskKey))); + + // 新增或更新任务 + enabledTasks.forEach(task -> { + if (!scheduledTasks.containsKey(task.getDataBaseName()) || + isCronModified(task)) { + cancelExistingTask(task.getDataBaseName()); + scheduleTask(task,commentModel); + } + }); + } + + private void scheduleTask(DataBaseInfo task, CommentModel commentModel) { + ScheduledFuture future = taskScheduler.schedule( + () -> executeTask(task.getDataBaseName(),commentModel), + new CronTrigger(task.getCronExpression()) + ); + scheduledTasks.put(task.getDataBaseName(), future); + } + + /** + * 业务逻辑执行 + * @param taskKey + */ + private void executeTask(String taskKey, CommentModel commentModel) { + isRuning=true; + log.info("execute task key:{}, commentModel:{}", taskKey, commentModel); + if(commentModel==null){ + commentModel =sxDataService.getCommentModel(); + } + if(StringUtils.isEmpty(commentModel.getSyncTime())){ + commentModel =sxDataService.getCommentModel(); + } + DataBaseInfo dataBaseInfo=sxDataService.getDataBaseInfo(commentModel); + sxDataService.SyncBranchList(dataBaseInfo,commentModel); + sxDataService.SyncCategory(dataBaseInfo,commentModel); + sxDataService.SyncGoods(dataBaseInfo,commentModel);//todo 暂时同步全部的商品如果后期修改,需要增加服务器的字段test + sxDataService.SyncVipList(dataBaseInfo,commentModel); + isRuning=false; + } + + private void cancelExistingTask(String taskKey) { + Optional.ofNullable(scheduledTasks.remove(taskKey)) + .ifPresent(future -> future.cancel(false)); + } + + private boolean isCronModified(DataBaseInfo newTask) { + DataBaseInfo dataBaseInfo= sxDataService.getDataBaseInfo(sxDataService.getCommentModel()); + return scheduledTasks.containsKey(newTask.getDataBaseName()) && + !dataBaseInfo.getCronExpression().equals(newTask.getCronExpression()); + } +} diff --git a/client/src/main/java/com/small/client/Utils/CommonUtil.java b/client/src/main/java/com/small/client/Utils/CommonUtil.java new file mode 100644 index 00000000..4f8db7e3 --- /dev/null +++ b/client/src/main/java/com/small/client/Utils/CommonUtil.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.small.client.Utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; + +public class CommonUtil { + + private final static String apiUrl = "http://4ei8850868ux.vicp.fun"; + + public static JSONObject sendPostRequestToSiXun(String urlPath, JSONObject params) { + String resp = HttpUtil.post(apiUrl + urlPath, params.toString()); + if (StrUtil.isBlank(resp)) { + return null; + } + + JSONObject respObj = JSONUtil.parseObj(resp); + + return respObj; + } + + /** + * 根据总条数和分页大小,求页数 + * + * @param total + * @param pageSize + * @return + */ + public static Integer getPagesCount(Integer total, Integer pageSize) { + if (total == null || pageSize == null || pageSize <= 0 || total <= 0) { + return 0; + } + + int pagesCount = 0; + pagesCount = total / pageSize; + + if (total % pageSize > 0) { + // 有余数 + pagesCount++; + } else { + if (pagesCount == 0) { + pagesCount = 1; + } + } + + return pagesCount; + } + + /** + * 接口是否成功执行返回 + * + * @param jsonObject + * @return + */ + public static Boolean isSuccess(JSONObject jsonObject) { + if (jsonObject == null) { + return false; + } + + return jsonObject.get("code") != null && jsonObject.getStr("code").equals("0"); + } + + /** + * 接口是否成功执行返回 + * + * @param jsonObject + * @return + */ + public static Boolean hasSuccessData(JSONObject jsonObject) { + if (jsonObject == null) { + return false; + } + + return jsonObject.get("code") != null && jsonObject.getStr("code").equals("0") && jsonObject.get("data") != null; + } + + /** + * 通过json节点表达式,获取节点json字符串,注:驼峰命名改成下划线命名 + * + * @param jsonObject + * @param expression json 节点表达式比如: data.list, msg, code + * @return + */ + public static String toUnderlineJson(JSONObject jsonObject, String expression) { + return StrUtil.toUnderlineCase(jsonObject.getByPath(expression, String.class)); + } + + +} diff --git a/client/src/main/java/com/small/client/Utils/CryptoUtils.java b/client/src/main/java/com/small/client/Utils/CryptoUtils.java new file mode 100644 index 00000000..6c99f73d --- /dev/null +++ b/client/src/main/java/com/small/client/Utils/CryptoUtils.java @@ -0,0 +1,110 @@ +package com.small.client.Utils; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class CryptoUtils { + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; + private static final String SECRET_KEY = "9f823ea6ab22785caf040e4cc3930619"; // 必须16/24/32字符 + + private static final String HASH_ALGORITHM_KEY = "appKey=a&sign=b&storeId=c"; + + /** + * 打包并加密字段 + */ + public static String packAndEncrypt(String appKey, String sign, String storeId) throws Exception { + String combined = String.format("appKey=%s&sign=%s&storeId=%s", appKey, sign, storeId); + return encrypt(combined); + } + + /** + * 32位字符串生成 + * @param input + * @return + * @throws NoSuchAlgorithmException + */ + public static String generate32CharMD5(String input) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] hashBytes = md.digest(input.getBytes()); + + StringBuilder hexString = new StringBuilder(); + for (byte b : hashBytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + + /** + * 解密并解包字段 + */ + public static Map decryptAndUnpack(String encryptedData) throws Exception { + String decrypted = decrypt(encryptedData); + Map result = new HashMap<>(); + String[] pairs = decrypted.split("&"); + for (String pair : pairs) { + String[] keyValue = pair.split("="); + if (keyValue.length == 2) { + result.put(keyValue[0], keyValue[1]); + } + } + return result; + } + + /** + * 加密 + * @param value + * @return + * @throws Exception + */ + private static String encrypt(String value) throws Exception { + SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + byte[] encryptedBytes = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(encryptedBytes); + } + + /** + * 解密 + * @param encryptedValue + * @return + * @throws Exception + */ + private static String decrypt(String encryptedValue) throws Exception { + SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + byte[] decodedBytes = Base64.getDecoder().decode(encryptedValue); + byte[] decryptedBytes = cipher.doFinal(decodedBytes); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } + + + // 示例用法 + public static void main(String[] args) throws Exception { + + String appKey = "d68397c4fb671bc024e24e1964b067cc35388818"; + String sign = "d68397c4fb671bc024e24e1964b067cc35388818"; + String storeId = "1"; + + // 打包加密 + String encrypted = packAndEncrypt(appKey, sign, storeId); + System.out.println("加密结果: " + encrypted); + + // 解密解包 + Map result = decryptAndUnpack(encrypted); + System.out.println("解密结果: " + result); + } +} diff --git a/client/src/main/java/com/small/client/Utils/FileUtils.java b/client/src/main/java/com/small/client/Utils/FileUtils.java new file mode 100644 index 00000000..b865a8da --- /dev/null +++ b/client/src/main/java/com/small/client/Utils/FileUtils.java @@ -0,0 +1,176 @@ +package com.small.client.Utils; + + +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Calendar; +import java.util.Date; + +@Slf4j +public class FileUtils { + + public static final String pathSeparator = System.getProperty("file.separator"); + public static final String FOLDER = System.getProperty("user.home") + pathSeparator+"uploaded"+pathSeparator; + public static final String GOODS = pathSeparator+"goods"+pathSeparator;//商品 + public static final String CATEGORY= pathSeparator+ "category"+pathSeparator;//分类 + public static final String BRAND = pathSeparator+"brand/"+pathSeparator;//品牌 + public static final String MEMBER= pathSeparator+"member"+pathSeparator;//会员 + + public static final String CLIENTSTALLPATH = System.getProperty("user.home") + pathSeparator+"cientStorePath"+pathSeparator; + + public static final String REFLESHDATE="refleshdate.txt"; + public static final String PRIMARYKEY="primaryKey.txt"; + + public static final String GOODS_TYPE = "goods";//商品 + public static final String CATEGORY_TYPE= "category";//分类 + public static final String BRAND_TYPE = "brand";//品牌 + public static final String MEMBER_TYPE= "member";//会员 + + public static final String okEnd = "ok";//后缀 + public static final String txtEnd = "txt";//后缀 + + public static String fileFormat = "%s_%s.%s";//good_1 + + public static String getSyncTypeFlag(String syncType){ + Calendar calendar=Calendar.getInstance(); + int year=calendar.get(Calendar.YEAR); + int month=calendar.get(Calendar.MONTH)+1; + int date=calendar.get(Calendar.DAY_OF_MONTH); + String result =FOLDER; + switch (syncType){ + case "1": + result=GOODS; + break; + case "2": + result=CATEGORY; + break; + case "3": + result=BRAND; + break; + case "4": + result=MEMBER; + break; + default: + break; + } + return result+year+pathSeparator+month+pathSeparator+date+pathSeparator; + } + + /** + * 创建文件 + * @param syncType + * @param page + * @return + */ + public File createFile(String syncType,Integer page){ + String path= getSyncTypeFlag(syncType+pathSeparator+page+pathSeparator); + File file=new File(path); + if(!file.exists()){ + file.mkdirs(); + } + return file; + } + + /** + * 创建文件 + * @param path + * @return + */ + public File createFile(String path){ + File file=new File(path); + if(!file.exists()){ + file.mkdirs(); + } + return file; + } + + /** + * 文件写入 + * @param filePath + */ + public void writeFile(String filePath,String fileName,String content){ + try { + FileWriter writer = new FileWriter(filePath+pathSeparator+fileName); + writer.write(content); + writer.close(); + log.info("文件写入成功!"); + } catch (IOException e) { + log.info("文件写入失败:{}", e.getMessage()); + } + } + + /** + * 根据类型获取文件名称 + * @param syncType + * @param page + * @return + */ + public String getFileName(String syncType ,Integer page,String endFix){ + String result=""; + switch (syncType){ + case "1": + result=GOODS_TYPE; + break; + case "2": + result=CATEGORY_TYPE; + break; + case "3": + result=BRAND_TYPE; + break; + case "4": + result=MEMBER_TYPE; + break; + default: + break; + } + return String.format(fileFormat, result,page,endFix); + } + + /** + * 创建文件 + * @param folderPath + * @param filePath + */ + public static void createFolderAndFileUsingFile(String folderPath, String filePath) { + File folder = new File(folderPath); + if (!folder.exists()) { + folder.mkdir(); + } + + File file = new File(filePath); + try { + if (!file.exists()) { + file.createNewFile(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + public static void copyFile(String srcFile, String destFile) { + String path= JarPathUtil.getRuntimePath(); + Path sourceFile = Paths.get(srcFile); + Path targetDir =Paths.get(destFile); + try { + Files.copy(sourceFile, targetDir.resolve(sourceFile.getFileName()), + StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public static void main(String[] args) { + FileUtils fileUtils= new FileUtils(); + File file=fileUtils.createFile("1",1); + System.out.printf("--"+file.getAbsoluteFile()); + fileUtils.writeFile(file.getAbsolutePath(),fileUtils.getFileName("1",2,txtEnd),"456"); + } + +} diff --git a/client/src/main/java/com/small/client/Utils/HttpUtils.java b/client/src/main/java/com/small/client/Utils/HttpUtils.java new file mode 100644 index 00000000..5bf17681 --- /dev/null +++ b/client/src/main/java/com/small/client/Utils/HttpUtils.java @@ -0,0 +1,107 @@ +package com.small.client.Utils; + +import cn.hutool.json.JSON; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.small.client.dto.StoreDbConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Slf4j +public class HttpUtils { + + public static final String SUCCESSCODE="0";//上传文件 + + public static final String URL_UPLOUP="/shop/sync/third/uploudSxData";//上传文件 + + + public static final String URL_SYNC_CATEGORY="/shop/sync/third/goods/category";//商品分类数据同步 + + public static final String URL_SYNC_BRAND="/shop/sync/third/goods/brand";//商品品牌数据同步 + + public static final String URL_SYNC_GOODS="/shop/sync/third/goods";//商品数据同步 + + public static final String URL_SYNC_MEMBER="/shop/sync/third/member"; + + public static final String URL_SYNC_GOODS_READ="/shop/sync/third/readSxData";//商品数据同步 + + public static final String URL_SYNC_GET_APPSIGN="/shop/sync/third/getAppSign";//获取密文 + + public static final String URL_SYNC_GET_DOWNCLIENTJAR="/shop/sync/app/downClientJar";//文件下载 + + public static final String URL_SYNC_GET_STOREdBCONFIG="/shop/sync/third/getStoreDbConfig";//文件下载 + + public static String postData(RestTemplate restTemplate, String url,Object modelObject){ + // 创建表单参数 +// MultiValueMap map = new LinkedMultiValueMap<>(); +// map.add("key1", "value1"); +// map.add("key2", "value2"); + + // 设置Content-Type为application/x-www-form-urlencoded + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + log.info(modelObject.toString()); + HttpEntity request = new HttpEntity<>(modelObject, headers); + + // 发送POST请求 + JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class); + assert jsonObject != null; + log.info(jsonObject.toString()); + return jsonObject.getStr("error_code"); + } + + public static String postData(RestTemplate restTemplate, String url,Object modelObject,String contentName){ + // 创建表单参数 +// MultiValueMap map = new LinkedMultiValueMap<>(); +// map.add("key1", "value1"); +// map.add("key2", "value2"); + + // 设置Content-Type为application/x-www-form-urlencoded + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + log.info(modelObject.toString()); + HttpEntity request = new HttpEntity<>(modelObject, headers); + + // 发送POST请求 + JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class); + assert jsonObject != null; + log.info(jsonObject.toString()); + if("OK".equals(jsonObject.get("resultCode"))){ + return jsonObject.getStr(contentName); + } + return null; + } + + public static StoreDbConfig postDataGetConfig(RestTemplate restTemplate, String url, Object modelObject){ + // 创建表单参数 +// MultiValueMap map = new LinkedMultiValueMap<>(); +// map.add("key1", "value1"); +// map.add("key2", "value2"); + + // 设置Content-Type为application/x-www-form-urlencoded + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + log.info(modelObject.toString()); + HttpEntity request = new HttpEntity<>(modelObject, headers); + + // 发送POST请求 + JSONObject jsonObject = restTemplate.postForObject(url, request, JSONObject.class); + assert jsonObject != null; + log.info(jsonObject.toString()); + if(0==jsonObject.getInt("error_code")){ + JSONObject object= jsonObject.getJSONObject("result"); + if(null!=object){ + return JSONUtil.toBean(object,StoreDbConfig.class); + } + } + return null; + } + +} diff --git a/client/src/main/java/com/small/client/Utils/JarPathUtil.java b/client/src/main/java/com/small/client/Utils/JarPathUtil.java new file mode 100644 index 00000000..78bc506f --- /dev/null +++ b/client/src/main/java/com/small/client/Utils/JarPathUtil.java @@ -0,0 +1,70 @@ +package com.small.client.Utils; + +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +@Slf4j +public class JarPathUtil { + /** + * 更健壮的获取JAR路径方法 + */ + public static String getJarPath() { + try { + // 获取当前类的URI + String jarPath = JarPathUtil.class + .getProtectionDomain() + .getCodeSource() + .getLocation() + .toURI() + .getPath(); + + // 处理Windows路径问题 + if (jarPath.startsWith("/") && System.getProperty("os.name").contains("Windows")) { + jarPath = jarPath.substring(1); + } + + return new File(jarPath).getAbsolutePath(); + } catch (URISyntaxException e) { + throw new RuntimeException("无法解析JAR文件URI", e); + } + } + + /** + * 使用NIO获取JAR所在目录 + */ + public static String getJarParentPath() { + try { + Path path = Paths.get(JarPathUtil.class.getProtectionDomain() + .getCodeSource() + .getLocation() + .toURI()); + return path.getParent().toString(); + } catch (URISyntaxException e) { + throw new RuntimeException("无法解析JAR文件URI", e); + } + } + public static String getRuntimePath() { + URL location = JarPathUtil.class.getProtectionDomain() + .getCodeSource() + .getLocation(); + String path = location.getPath(); + + // 判断是否在IDE中运行(class文件) + if (path.endsWith(".jar")) { + // JAR运行模式 + return new File(path).getParent(); + } else { + // IDE运行模式,返回项目目录 + return new File("").getAbsolutePath(); + } + } + + public static void main(String[] args) { + log.info(getRuntimePath()); + } +} diff --git a/client/src/main/java/com/small/client/comment/DicEnum.java b/client/src/main/java/com/small/client/comment/DicEnum.java new file mode 100644 index 00000000..a88f1031 --- /dev/null +++ b/client/src/main/java/com/small/client/comment/DicEnum.java @@ -0,0 +1,30 @@ +package com.small.client.comment; + +import lombok.Getter; + +public enum DicEnum { + //1-品牌,2-分类,3-商品,4-会员 + SYNCTYPE_1("1","品牌","syncType","同步类型"), + SYNCTYPE_2("2","分类","syncType","同步类型"), + SYNCTYPE_3("3","商品","syncType","同步类型"), + SYNCTYPE_4("4","会员","syncType","同步类型"), + ; + + @Getter + private String code; + @Getter + private String name; + @Getter + private String dicType; + @Getter + private String description; + + DicEnum(String code, String name, String dicType, String description) { + this.code = code; + this.name = name; + this.dicType = dicType; + this.description = description; + } + + +} diff --git a/client/src/main/java/com/small/client/comment/UrlComment.java b/client/src/main/java/com/small/client/comment/UrlComment.java new file mode 100644 index 00000000..2c02301c --- /dev/null +++ b/client/src/main/java/com/small/client/comment/UrlComment.java @@ -0,0 +1,11 @@ +package com.small.client.comment; + +public class UrlComment { + + public static String url="";//获取shop的数据库基本信息 todo + + public static String UrlSynShop="";//商品同步接口 + public static String UrlSynCategory="";//商品种类同步接口 + + public static String UrlSynProduct=""; +} diff --git a/client/src/main/java/com/small/client/config/ClientConfig.java b/client/src/main/java/com/small/client/config/ClientConfig.java new file mode 100644 index 00000000..c062e31c --- /dev/null +++ b/client/src/main/java/com/small/client/config/ClientConfig.java @@ -0,0 +1,14 @@ +package com.small.client.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class ClientConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/client/src/main/java/com/small/client/config/TaskConfig.java b/client/src/main/java/com/small/client/config/TaskConfig.java new file mode 100644 index 00000000..a4f41f72 --- /dev/null +++ b/client/src/main/java/com/small/client/config/TaskConfig.java @@ -0,0 +1,18 @@ +package com.small.client.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; + +import java.util.concurrent.Executors; + +@Configuration +@EnableScheduling +public class TaskConfig { + @Bean + public TaskScheduler taskScheduler() { + return new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(10)); // 使用默认线程池 + } +} diff --git a/client/src/main/java/com/small/client/controller/WebController.java b/client/src/main/java/com/small/client/controller/WebController.java new file mode 100644 index 00000000..737b0be9 --- /dev/null +++ b/client/src/main/java/com/small/client/controller/WebController.java @@ -0,0 +1,79 @@ +package com.small.client.controller; + +import com.small.client.Utils.HttpUtils; +import com.small.client.dto.DataBaseInfo; +import com.small.client.dto.SyncGoodsSearchModel; +import com.small.client.service.SxDataService; +import com.small.client.service.WebClientService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/client") +@Slf4j +public class WebController { + @Autowired + private WebClientService webClientService; + @Autowired + private SxDataService sxDataService; + + @RequestMapping("/upload") + public void upload(){ + System.out.println("upload"); + //webClientService.uploudSxData(); + } + + @RequestMapping("/synBrand") + public void synBrand(){ + log.info("synBrand"); + sxDataService.getAppSign(); + + sxDataService.SyncBranchList(new DataBaseInfo(),sxDataService.getCommentModel()); + } + + @RequestMapping("/syncCategory") + public void syncCategory(){ + log.info("syncCategory"); + sxDataService.getAppSign(); + sxDataService.SyncCategory(new DataBaseInfo(),sxDataService.getCommentModel()); + } + + @RequestMapping("/syncGoods") + public void syncGoods(){ + log.info("syncGoods"); + sxDataService.getAppSign(); + sxDataService.SyncGoods(new DataBaseInfo(),sxDataService.getCommentModel()); + } + + @RequestMapping("/synvip") + public void synvip(){ + log.info("synvip"); + sxDataService.getAppSign(); + sxDataService.SyncVipList(new DataBaseInfo(),sxDataService.getCommentModel()); + } + + @RequestMapping("/getAppSign") + public void getAppSign(){ + log.info("getAppSign"); + sxDataService.getAppSign(); + } + + @RequestMapping("/downLoadClient") + public void downLoadClient(){ + log.info("downLoadClient"); + sxDataService.downLoadClient(); + } + + @RequestMapping("/udpateAndStart") + public void updateAndStart(){ + sxDataService.checkForUpdates(); + } + + @RequestMapping("/getDataBaseInfo") + public void getDataBaseInfo(){ + sxDataService.getDataBaseInfo(sxDataService.getCommentModel()); + } + +} diff --git a/client/src/main/java/com/small/client/dao/BaseDao.java b/client/src/main/java/com/small/client/dao/BaseDao.java new file mode 100644 index 00000000..d9d3e948 --- /dev/null +++ b/client/src/main/java/com/small/client/dao/BaseDao.java @@ -0,0 +1,246 @@ +package com.small.client.dao; + +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; +import com.microsoft.sqlserver.jdbc.SQLServerException; + +import com.small.client.dto.ResultDto; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +@Slf4j +public class BaseDao { + + private final static String DEFAULT_IP="127.0.0.1"; + private final static String DEFAULT_DATABASE="hbposev9"; + private final static String DEFAULT_USERNAME="sa"; + private final static String DEFAULT_PWD="123456"; + private final static int PortNumber=1433; + private final static int LoginTimeout=10; + /** + * + * 动态获取数据库连接 + * @param ip 数据库ip+ + * @param username 用户名 + * @param password 密码 todo 需要加密 + * @param dataBaseName 数据库名称 + * @return + */ + public Connection getConnection(String ip, String username, String password,Integer port, String dataBaseName){ + Connection conn=null; + SQLServerDataSource sqlServerDataSource=new SQLServerDataSource(); + sqlServerDataSource.setDatabaseName(dataBaseName==null?DEFAULT_DATABASE:dataBaseName); + sqlServerDataSource.setServerName(ip==null?DEFAULT_IP:ip); + sqlServerDataSource.setPortNumber(port==null?PortNumber:port); + sqlServerDataSource.setLoginTimeout(LoginTimeout); + sqlServerDataSource.setPassword(password==null?DEFAULT_PWD:password); + sqlServerDataSource.setUser(username==null?DEFAULT_USERNAME:username); + try { + conn=sqlServerDataSource.getConnection(); + } catch (SQLServerException e) { + log.info("数据库连接异常方法{}异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getConnection",e.getMessage()); + throw new RuntimeException(e); + } + + return conn; + } + + /** + * 关闭数据库连接 + * @param conn + */ + public void Close(Connection conn){ + if(conn!=null){ + try { + conn.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + /** + * 返回游标和连接 减少服务器的占用内存 + * @param ip + * @param username + * @param password + * @param dataBaseName + * @return ResultDto + */ + public ResultDto baseFindList(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String where){ + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + String sql="select * from %s %s"; + sql=String.format(sql, table,where); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + log.info(sql); + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindList",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + + } + + /** + * 带分页数据 + * @param ip + * @param username + * @param password + * @param dataBaseName + * @param table + * @return + */ + public ResultDto baseFindListPage(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String orderColumn, int pageNo, int pageSize,String where){ + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + int start=(pageNo-1)*pageSize+1; + int end=pageNo*pageSize; + String sql=" select * from( " + + " select ROW_NUMBER() OVER(ORDER BY %s) as rowId,* from %s %s" + + " ) as r where rowId between %s and %s"; + sql=String.format(sql, orderColumn,table,where,start,end); + log.info(sql); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindListPage",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + } + + public Integer getBaseTotal(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String where){ + int total=0; + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + try { + String sql="select count(*) from %s %s"; + sql=String.format(sql, table,where); + log.info(sql); + PreparedStatement ps= connection.prepareStatement(sql); + ResultSet rs=ps.executeQuery(); + while (rs.next()){ + total=rs.getInt(1); + } + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getBaseTotal",e.getMessage()); + throw new RuntimeException(e); + } + finally { + try { + connection.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return total; + } + + + public Integer getBaseJoinTotal(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String orderColumn,String rightSelect,String where){ + int total=0; + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + try { + String sql=" select COUNT(*) from( " + + " select ROW_NUMBER() OVER(ORDER BY b.%s) as rowId,b.*,%s from %s b left join %s t on b.%s=t.%s %s" + + " ) r"; + sql=String.format(sql, orderColumn,rightSelect,table,joinTable,onLeft,onRight,where); + log.info(sql); + PreparedStatement ps= connection.prepareStatement(sql); + ResultSet rs=ps.executeQuery(); + while (rs.next()){ + total=rs.getInt(1); + } + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.getBaseTotal",e.getMessage()); + throw new RuntimeException(e); + } + finally { + try { + connection.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return total; + } + + + /** + * 带分页数据关联分页查询 + * @param ip + * @param username + * @param password + * @param dataBaseName + * @param table + * @return + */ + public ResultDto baseFindListJoinPage(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String orderColumn,String rightSelect, int pageNo, int pageSize,String where){ + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + int start=(pageNo-1)*pageSize+1; + int end=pageNo*pageSize; + String sql=" select * from( " + + " select ROW_NUMBER() OVER(ORDER BY b.%s) as rowId,b.*,%s from %s b left join %s t on b.%s=t.%s %s" + + " ) as r where rowId between %s and %s"; + sql=String.format(sql, orderColumn,rightSelect,table,joinTable,onLeft,onRight,where,start,end); + log.info(sql); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindListJoinPage",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + } + + /** + * + * @param ip + * @param username + * @param password + * @param dataBaseName + * @param table + * @param joinTable + * @param onLeft + * @param onRight + * @param rightSelect + * @param where + * @return + */ + public ResultDto baseFindListJoin(String ip, String username, String password,Integer portNumber, String dataBaseName, String table,String joinTable,String onLeft,String onRight,String rightSelect, String where){ + Connection connection=getConnection(ip,username,password,portNumber,dataBaseName); + String sql= "select b.*,%s from %s b left join %s t on b.%s=t.%s %s " ; + sql=String.format(sql,rightSelect,table,joinTable,onLeft,onRight,where); + log.info(sql); + ResultDto resultDto=new ResultDto(); + ResultSet rs=null; + try { + PreparedStatement ps= connection.prepareStatement(sql); + rs = ps.executeQuery(); + } catch (SQLException e) { + log.info("数据库查询异常方法{},异常信息{}","com.suisung.mall.shop.sixun.dao.BaseDao.baseFindListJoin",e.getMessage()); + throw new RuntimeException(e); + } + resultDto.setResultSet(rs); + resultDto.setConnection(connection); + return resultDto; + } + +} diff --git a/client/src/main/java/com/small/client/dao/SxDataDao.java b/client/src/main/java/com/small/client/dao/SxDataDao.java new file mode 100644 index 00000000..85fc645e --- /dev/null +++ b/client/src/main/java/com/small/client/dao/SxDataDao.java @@ -0,0 +1,448 @@ +package com.small.client.dao; + + +import com.small.client.dto.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.Charset; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * 考虑到每个思迅软件都是自己的数据,所以采用动态获取的方式获取数据 + * 数据库为MS SQL + * todo 如果考虑到数据量需要分页多线程 + */ +@Service +@Slf4j +public class SxDataDao extends BaseDao{ + + private final static String T_BD_ITEM_CLS="t_bd_item_cls";//商品分类 + private final static String T_BD_ITEM_INFO="t_bd_item_info";//商品表 + private final static String T_RM_VIP_INFO="t_rm_vip_info";//会员表 + + private final static String ITEM_CLSNO="item_clsno";//商品分类排序字段 + private final static String ITEM_NO="item_no";//商品排序字段 + private final static String CARD_ID="card_id";//会员表排序字段 + + + private final static String T_BD_BASE_CODE="t_bd_base_code";//品牌表 + private final static String T_BD_BASECODE_TYPE="t_bd_basecode_type";//品牌表 + private final static String TYPE_NO="type_no";//品牌排序字段 + + private final static String T_IM_BRANCH_STOCK="t_im_branch_stock";//库存表 + + private final static String T_RM_SPEC_PRICE="t_rm_spec_price";//活动表 + + public final static Integer PAGESIZE=500; + + public final static String DEFALTWHERE="where 1=1"; + + public final static String DEFAULT_IMG="https://digitalassets.tesla.com/tesla-contents/image/upload/f_auto,q_auto/Homepage-Model-Y-2-Promo-Hero-Tablet-CN.png"; + + + /** + * 查找商品分类数据 + * @param dataBaseInfo + */ + public List findTBdItemClsList(DataBaseInfo dataBaseInfo){ + ResultDto resultDto=baseFindList(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,DEFALTWHERE); + ResultSet rs= resultDto.getResultSet(); + List sxSyncCategories=new ArrayList<>(); + SxSyncCategory sxSyncCategory=null; + try { + while (rs.next()) { + sxSyncCategory=new SxSyncCategory(); + sxSyncCategory.setItem_clsname(rs.getString("item_clsname").trim());//分类名称 + if(null!=rs.getString("cls_parent")){ + sxSyncCategory.setCls_parent(rs.getString("cls_parent").trim());//父级编码 + } + sxSyncCategory.setItem_clsno(rs.getString("item_clsno").trim());//分类编码 +// System.out.printf(rs.getString("item_clsno"));//分类编码 +// System.out.printf(rs.getString("item_clsname")+"\t");//分类名称 +// System.out.print(rs.getString("cls_parent")+"\t");//父级编码 +// System.out.print(rs.getString("item_flag")+"\t" + "\n");//显示标识 + sxSyncCategories.add(sxSyncCategory); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return sxSyncCategories; + } + + /** + * 分页查找商品分类数据 + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findTBdItemClsListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){ + ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,ITEM_CLSNO,pageNo,pageSize,DEFALTWHERE); + ResultSet rs= resultDto.getResultSet(); + List sxSyncCategories=new ArrayList<>(); + SxSyncCategory sxSyncCategory=null; + try { + while (rs.next()) { + sxSyncCategory=new SxSyncCategory(); + sxSyncCategory.setItem_clsname(rs.getString("item_clsname"));//分类名称 + sxSyncCategory.setCls_parent(rs.getString("cls_parent"));//父级编码 + sxSyncCategory.setItem_clsno(rs.getString("item_clsno"));//分类编码 +// System.out.printf(rs.getString("item_clsno"));//分类编码 + // log.info(rs.getString("item_clsname")+"\t");//分类名称 + //log.info(rs.getString("cls_parent")+"\t");//父级编码 + //log.info(rs.getString("item_flag")+"\t" + "\n");//显示标识 + sxSyncCategories.add(sxSyncCategory); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return sxSyncCategories; + } + + /** + * 获取商品分类TBdItemCls表的数量 + * @param dataBaseInfo + * @return + */ + public Integer getTBdItemClsTotal(DataBaseInfo dataBaseInfo){ + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_CLS,DEFALTWHERE); + } + + /** + * 获取商品表t_bd_item_info表的数量 + * @param dataBaseInfo + * @return + */ + public int getTBditemInfoTotal(DataBaseInfo dataBaseInfo){ +// String where =DEFALTWHERE; +// if(syncGoodsSearchModel!=null){ +// if(dataBaseInfo.getWhere()!=null){ +// where+= dataBaseInfo.getWhere(); +// } +// } + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_BD_ITEM_INFO,dataBaseInfo.getWhere()); + } + + /** + * 获取商品表t_bd_item_info表的数量 + * @param dataBaseInfo + * @return + */ + public int getTBditemInfoJoninTotal(DataBaseInfo dataBaseInfo){ + return getBaseJoinTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName() + , T_BD_ITEM_INFO + ,T_IM_BRANCH_STOCK + ,"item_no" + ,"item_no" + ,ITEM_CLSNO + ,"t.stock_qty,t.oper_date" + ,dataBaseInfo.getWhere()==null?DEFALTWHERE:dataBaseInfo.getWhere()); + } + + /** + * 获取会员表t_rm_vip_info表的数量 + * @param dataBaseInfo + * @return + */ + public int getTrmVipInfoTotal(DataBaseInfo dataBaseInfo){ + return getBaseTotal(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_RM_VIP_INFO,dataBaseInfo.getWhere()); + } + + + /** + * 分页查找商品数据 + * 表T_BD_ITEM_INFO + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findBditemInfoListPage(DataBaseInfo dataBaseInfo,int pageNo,int pageSize){ + ResultDto resultDto=baseFindListJoinPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName() + , T_BD_ITEM_INFO + ,T_IM_BRANCH_STOCK + ,"item_no" + ,"item_no" + ,ITEM_CLSNO + ,"t.stock_qty,t.oper_date" + ,pageNo,pageSize,dataBaseInfo.getWhere()==null?DEFALTWHERE:dataBaseInfo.getWhere()); + ResultSet rs= resultDto.getResultSet(); + List sxSyncGoodses=new ArrayList<>(); + SxSyncGoods sxSyncGoods=null; + try { + while (rs.next()) { + sxSyncGoods=new SxSyncGoods(); + BigDecimal price=new BigDecimal(rs.getString("price")); + BigDecimal salePrice=new BigDecimal(rs.getString("sale_price")); + if(salePrice.compareTo(new BigDecimal("0"))>0){ + try{ + BigDecimal gross= salePrice.subtract(price).divide(salePrice,4, RoundingMode.HALF_UP); + sxSyncGoods.setGross_margin(gross);//毛利率 + }catch (RuntimeException e){ + log.info("运行错误:{}",e.getMessage()); + log.info(String.valueOf(rs.getString("sale_price"))); + } + + }else { + sxSyncGoods.setGross_margin(new BigDecimal("0"));//毛利率 + } + sxSyncGoods.setItem_no(rs.getString("item_no"));//货号 + sxSyncGoods.setItem_subname(rs.getString("item_subname"));//商品名称 + sxSyncGoods.setItem_subno(rs.getString("item_subno"));//商品条码 + + sxSyncGoods.setBig_cls_name("9999");//商品大类 todo 如何关联 + sxSyncGoods.setSmall_cls_name(rs.getString("item_clsno").trim());//商品小类 todo 如何关联 + + sxSyncGoods.setItem_size(rs.getString("item_size"));//规格 + sxSyncGoods.setUnit_no(rs.getString("unit_no"));//单位 todo + sxSyncGoods.setStock(rs.getBigDecimal("stock_qty"));//库存数量 todo item_stock? + + sxSyncGoods.setPrice(rs.getBigDecimal("price"));//进货价 + sxSyncGoods.setSale_price(rs.getBigDecimal("sale_price"));//零售价 + + sxSyncGoods.setVip_price(rs.getBigDecimal("vip_price"));//会员价 + sxSyncGoods.setVip_acc_flag(rs.getBigDecimal("vip_acc_flag"));//允许积分 + sxSyncGoods.setVip_acc_num(rs.getBigDecimal("vip_acc_num"));//积分值 + sxSyncGoods.setSale_flag(rs.getInt("main_Sale_flag"));//商品状态 todo 是main_Sale_flag? + sxSyncGoods.setItem_rem(rs.getString("item_rem"));//助记码 + sxSyncGoods.setBuild_date(rs.getString("build_date"));//生产日期 todo + sxSyncGoods.setValid_days(getStopDate(rs));//保质期 todo stop_date-build_date? + + sxSyncGoods.setItem_brand_name(rs.getString("item_brandname")); + sxSyncGoods.setItemBrand(rs.getString("item_brand")); + sxSyncGoods.setItem_clsno(rs.getString("item_clsno").trim()); + sxSyncGoods.setItem_size(rs.getString("item_size")); + + sxSyncGoodses.add(sxSyncGoods); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return sxSyncGoodses; + } + + private static String getStopDate(ResultSet rs) throws SQLException { + return rs.getString("stop_date"); + } + + + /** + * 分页查找会员数据 + * RM_VIP_INFO + * @param dataBaseInfo + * @param pageNo + * @param pageSize + */ + public List findRmVipInfoListPage(DataBaseInfo dataBaseInfo, int pageNo, int pageSize){ + ResultDto resultDto=baseFindListPage(dataBaseInfo.getIp(),dataBaseInfo.getUserName(),dataBaseInfo.getPassword(),dataBaseInfo.getDbPort(),dataBaseInfo.getDataBaseName(),T_RM_VIP_INFO,CARD_ID,pageNo,pageSize,dataBaseInfo.getWhere()); + ResultSet rs= resultDto.getResultSet(); + List sxSyncVips=new ArrayList<>(); + SxSyncVip sxSyncVip=null; + try { + while (rs.next()) { + sxSyncVip = new SxSyncVip(); + int cardStatus=rs.getInt("card_status"); + if(cardStatus!=1){ + sxSyncVip.setVip_name(rs.getString("vip_name"));//会员名称 + sxSyncVip.setVip_sex(rs.getString("vip_sex"));//会员名称 + sxSyncVip.setMobile(rs.getString("mobile"));//会员名称 + sxSyncVip.setBirthday(rs.getString("birthday"));//会员生日 + sxSyncVip.setCard_type(rs.getString("card_type")==null?"v1":rs.getString("card_type"));//会员生日 + sxSyncVip.setCard_no(rs.getString("card_no"));//会员卡号 + sxSyncVip.setCard_no(rs.getString("now_acc_num"));//会员积分 + sxSyncVip.setCard_no(rs.getString("residual_amt"));//储值余额 + sxSyncVip.setCard_no(rs.getString("vip_start_date"));//建档日期 + + log.info(rs.getString("vip_name"));//会员名称 + log.info(rs.getString("mobile"));//会员手机号 + log.info(rs.getString("vip_sex"));//会员性别 + log.info(rs.getString("birthday"));//会员生日 + log.info(rs.getString("card_no"));//会员卡号 + log.info(rs.getString("card_type"));//会员等级 + log.info("{}",rs.getBigDecimal("residual_amt"));//储值余额 + log.info("{}",rs.getBigDecimal("now_acc_num"));//会员积分 + log.info(rs.getString("vip_start_date"));//建档日期 + log.info("{}",rs.getInt("card_status"));//会员状态 + } + + sxSyncVips.add(sxSyncVip); + } + }catch (SQLException e){ + throw new RuntimeException(e); + } + return sxSyncVips; + } + + /** + * 获取品牌数据 + * @param dataBaseInfo + */ + public List getBdBrandList(DataBaseInfo dataBaseInfo) { + String where="where t.type_name='品牌'"; + ResultDto resultDto=baseFindListJoin(dataBaseInfo.getIp() + ,dataBaseInfo.getUserName() + ,dataBaseInfo.getPassword() + ,dataBaseInfo.getDbPort() + ,dataBaseInfo.getDataBaseName() + ,T_BD_BASE_CODE + ,"t_bd_basecode_type" + ,"type_no" + ,"type_no" + ,"t.type_name" + ,where); + ResultSet rs= resultDto.getResultSet(); + List brandModels=new ArrayList<>(); + try { + while (rs.next()) { + BrandModel brandModel=new BrandModel(); + brandModel.setBrand_name(rs.getString("code_name")); + brandModel.setBrand_desc(rs.getString("code_name")); + brandModel.setCodeId(rs.getString("code_id")); + brandModel.setBrand_image(""); + brandModel.setCategory("0"); + brandModel.setBrand_recommend("0");//是否推荐 + brandModels.add(brandModel); + // log.info(rs.getString("type_no")+"--"+rs.getString("code_name"));//分类编码-分类名称 + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return brandModels; + } + + /** + * 获取库存数据 + * @return + */ + public List getImBranchStockList(DataBaseInfo dataBaseInfo,String where){ + ResultDto resultDto=baseFindList(dataBaseInfo.getIp() + ,dataBaseInfo.getUserName() + ,dataBaseInfo.getPassword() + ,dataBaseInfo.getDbPort() + ,dataBaseInfo.getDataBaseName() + ,T_IM_BRANCH_STOCK + ,where); + ResultSet rs= resultDto.getResultSet(); + List branchStocks=new ArrayList<>(); + try { + while (rs.next()) { + ImBranchStock brandModel=new ImBranchStock(); + brandModel.setBranchNo(rs.getString("branch_no")); + brandModel.setStockQty(rs.getBigDecimal("stock_qty")); + brandModel.setItemNo(rs.getString("item_no")); + brandModel.setPerDate(rs.getString("oper_date")); + branchStocks.add(brandModel); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return branchStocks; + } + + /** + *获取促销活动价格 时段特价单 + * @param dataBaseInfo + * @return + */ + public List getSpecPriceList(DataBaseInfo dataBaseInfo){ + ResultDto resultDto=baseFindList(dataBaseInfo.getIp() + ,dataBaseInfo.getUserName() + ,dataBaseInfo.getPassword() + ,dataBaseInfo.getDbPort() + ,dataBaseInfo.getDataBaseName() + ,"T_RM_SPEC_PRICE" + ,"where special_type ='0'"); + ResultSet rs= resultDto.getResultSet(); + List specPriceDtos=new ArrayList<>(); + try { + while (rs.next()) { + SpecPriceDto specPriceDto=new SpecPriceDto(); + specPriceDto.setItemNo(rs.getString("item_no"));// + specPriceDto.setOldPrice(rs.getBigDecimal("old_price"));//原价 + specPriceDto.setSpecPrice(rs.getBigDecimal("spe_price"));//特价 + specPriceDto.setSpecPrice(rs.getBigDecimal("sale_qty"));//限购 + specPriceDto.setDiscountType("0"); + specPriceDtos.add(specPriceDto); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return specPriceDtos; + } + + /** + * 折扣商品 + * @param dataBaseInfo + * @return + */ + public List getDiscountPriceList(DataBaseInfo dataBaseInfo){ + ResultDto resultDto=baseFindList(dataBaseInfo.getIp() + ,dataBaseInfo.getUserName() + ,dataBaseInfo.getPassword() + ,dataBaseInfo.getDbPort() + ,dataBaseInfo.getDataBaseName() + ,T_RM_SPEC_PRICE + ,"where special_type in('6','G')"); + ResultSet rs= resultDto.getResultSet(); + List specPriceDtos=new ArrayList<>(); + try { + while (rs.next()) { + SpecPriceDto specPriceDto=new SpecPriceDto(); + specPriceDto.setItemNo(rs.getString("item_no"));// + specPriceDto.setDiscount(rs.getBigDecimal("discount"));//原价 + specPriceDto.setDiscountType("1"); + specPriceDtos.add(specPriceDto); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + try { + resultDto.getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + return specPriceDtos; + } + +} diff --git a/client/src/main/java/com/small/client/dto/BrandModel.java b/client/src/main/java/com/small/client/dto/BrandModel.java new file mode 100644 index 00000000..dbfaf276 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/BrandModel.java @@ -0,0 +1,27 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BrandModel implements Serializable { + @ApiModelProperty("品牌名称") + private String brand_name; + + @ApiModelProperty("品牌编号") + private String codeId; + + @ApiModelProperty("品牌描述") + private String brand_desc; + + @ApiModelProperty("品牌分类") + private String category; + + @ApiModelProperty("图片") + private String brand_image; + + @ApiModelProperty("是否推荐") + private String brand_recommend; +} diff --git a/client/src/main/java/com/small/client/dto/CommentModel.java b/client/src/main/java/com/small/client/dto/CommentModel.java new file mode 100644 index 00000000..2b39159e --- /dev/null +++ b/client/src/main/java/com/small/client/dto/CommentModel.java @@ -0,0 +1,17 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class CommentModel { + @ApiModelProperty("店铺的key") + private String appKey; + @ApiModelProperty("店铺的密钥") + private String sign; + @ApiModelProperty("店铺的id") + private String storeId; + + @ApiModelProperty(value = "同步时间-用于增量同步,大于这个时间证明是增量") + private String syncTime;//同步时间 +} diff --git a/client/src/main/java/com/small/client/dto/DataBaseInfo.java b/client/src/main/java/com/small/client/dto/DataBaseInfo.java new file mode 100644 index 00000000..422ff5de --- /dev/null +++ b/client/src/main/java/com/small/client/dto/DataBaseInfo.java @@ -0,0 +1,33 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class DataBaseInfo { + @ApiModelProperty("数据库IP") + private String ip; + @ApiModelProperty("用户名") + private String userName; + @ApiModelProperty("密码") + private String password; + @ApiModelProperty("数据库名称") + private String dataBaseName; + @ApiModelProperty("条件") + private String where; + @ApiModelProperty(value = "数据库端口") + private Integer dbPort; + @ApiModelProperty(value = "定时同步的cron表达式") + private String cronExpression; + @ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)") + private String syncMode; + + @ApiModelProperty(value = "商品分类") + private String categoryName; + + @ApiModelProperty(value = "01全量,02增量") + private String syncType; + + @ApiModelProperty(value = "操作时间") + private String operDate; +} diff --git a/client/src/main/java/com/small/client/dto/ImBranchStock.java b/client/src/main/java/com/small/client/dto/ImBranchStock.java new file mode 100644 index 00000000..836a55ac --- /dev/null +++ b/client/src/main/java/com/small/client/dto/ImBranchStock.java @@ -0,0 +1,18 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ImBranchStock { + @ApiModelProperty("商品编号") + private String itemNo; + @ApiModelProperty("商标编号") + private String branchNo; + @ApiModelProperty("库存") + private BigDecimal stockQty; + @ApiModelProperty("操作时间") + private String perDate; +} diff --git a/client/src/main/java/com/small/client/dto/ProductImage.java b/client/src/main/java/com/small/client/dto/ProductImage.java new file mode 100644 index 00000000..ff28ae69 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/ProductImage.java @@ -0,0 +1,17 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class ProductImage { + @ApiModelProperty("图片路径") + private String image_url; + @ApiModelProperty("推荐值") + private String seq; + @ApiModelProperty("介绍") + private String desc; + @ApiModelProperty("是否默认") + private String is_default; + +} diff --git a/client/src/main/java/com/small/client/dto/PromotionDetail.java b/client/src/main/java/com/small/client/dto/PromotionDetail.java new file mode 100644 index 00000000..bad64429 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/PromotionDetail.java @@ -0,0 +1,17 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class PromotionDetail { + + @ApiModelProperty("活动id") + private String activity_id; + @ApiModelProperty("活动名称") + private String activity_name; + @ApiModelProperty("价格") + private String price; + @ApiModelProperty("介绍") + private String intro; +} diff --git a/client/src/main/java/com/small/client/dto/ResultDto.java b/client/src/main/java/com/small/client/dto/ResultDto.java new file mode 100644 index 00000000..a5cd2057 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/ResultDto.java @@ -0,0 +1,15 @@ +package com.small.client.dto; + +import lombok.Data; + +import java.sql.Connection; +import java.sql.ResultSet; + +@Data +public class ResultDto { + + private Connection connection; + + private ResultSet resultSet; + +} diff --git a/client/src/main/java/com/small/client/dto/SpecPriceDto.java b/client/src/main/java/com/small/client/dto/SpecPriceDto.java new file mode 100644 index 00000000..e03dd15b --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SpecPriceDto.java @@ -0,0 +1,19 @@ +package com.small.client.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class SpecPriceDto { + + private String itemNo; + private BigDecimal oldPrice;//原价 + private BigDecimal specPrice;//折后价 + + private BigDecimal discount;//折扣('6','G') + + private Integer saleQty;//限购 + + private String discountType;//折扣类型 0-特价,1打折 +} diff --git a/client/src/main/java/com/small/client/dto/StoreDbConfig.java b/client/src/main/java/com/small/client/dto/StoreDbConfig.java new file mode 100644 index 00000000..1678039a --- /dev/null +++ b/client/src/main/java/com/small/client/dto/StoreDbConfig.java @@ -0,0 +1,64 @@ +package com.small.client.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class StoreDbConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "主键ID") + private Long id; + + @ApiModelProperty(value = "店铺ID") + private String storeId; + + @ApiModelProperty(value = "数据库类型(mysql/oracle/sqlserver等)") + private String dbType = "sqlserver"; + + @ApiModelProperty(value = "数据库名称") + private String dbName; + + @ApiModelProperty(value = "数据库IP地址") + private String dbIp; + + @ApiModelProperty(value = "数据库端口") + private Integer dbPort; + + @ApiModelProperty(value = "数据库用户名") + private String dbUsername; + + @ApiModelProperty(value = "数据库密码(建议加密存储)") + private String dbPassword; + + @ApiModelProperty(value = "是否有外网访问(0:无,1:有)") + private String hasInternet; + + @ApiModelProperty(value = "同步模式(1:定时同步,2:间隔同步)") + private String syncMode; + + @ApiModelProperty(value = "是否启用(0:否,1:是)") + private String hasStart; + + @ApiModelProperty(value = "定时同步的cron表达式") + private String cronExpression; + + @ApiModelProperty(value = "商品分类") + private String categoryName; + + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @ApiModelProperty(value = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + @ApiModelProperty(value = "备注信息") + private String remark; +} diff --git a/client/src/main/java/com/small/client/dto/SxCategoryModel.java b/client/src/main/java/com/small/client/dto/SxCategoryModel.java new file mode 100644 index 00000000..168e5b9b --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SxCategoryModel.java @@ -0,0 +1,32 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 模型对应 + */ +@Data +public class SxCategoryModel { + //模型对应ShopBaseProductCategory start + private String parent_name;//暂时不用 + @ApiModelProperty(value = "商品分类名称") + private String category_name; + @ApiModelProperty(value = "分类图片") + private String category_image; + @ApiModelProperty(value = "是否允许虚拟商品(ENUM):1-是; 0-否") + private Integer category_virtual_enable; + @ApiModelProperty(value = "分佣比例-百分比") + private BigDecimal category_commission_rate; + // private String type_name;//todo 看代码没有用,使用的是product_type + //模型对应ShopBaseProductCategory end + @ApiModelProperty(value = "产品类型") + private String product_type; + @ApiModelProperty(value = "第一级父类") + private String first_category_name; + @ApiModelProperty(value = "第二级父类") + private String second_category_name; + +} diff --git a/client/src/main/java/com/small/client/dto/SxGoosModel.java b/client/src/main/java/com/small/client/dto/SxGoosModel.java new file mode 100644 index 00000000..ed570893 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SxGoosModel.java @@ -0,0 +1,103 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 思迅同步商品数据入口数据 + */ +@Data +public class SxGoosModel { + + @ApiModelProperty("商品名称") + private String product_name; + + @ApiModelProperty("商品货号") + private String product_number; + + @ApiModelProperty("商品条形码") + private String product_barcode; + + @ApiModelProperty("一级分类") + private String first_category_name; + + @ApiModelProperty("二级分类") + private String second_category_name; + + @ApiModelProperty("三级分类") + private String three_category_name; + + @ApiModelProperty("产品类型") + private String product_type; + + @ApiModelProperty("商品种类") + private String product_kind; + + @ApiModelProperty("成本价") + private BigDecimal cost_price; + + @ApiModelProperty("零售价") + private BigDecimal price; + + @ApiModelProperty("原价") + private BigDecimal original_price; + + @ApiModelProperty("商品价格") + private BigDecimal retail_price; + + @ApiModelProperty("会员价") + private BigDecimal member_price; + + @ApiModelProperty("库存") + private BigDecimal stock; + + @ApiModelProperty("毛利率") + private BigDecimal gross_margin; + + @ApiModelProperty("规格单位") + private String unit; + + @ApiModelProperty("可用积分") + private BigDecimal can_piont; + + @ApiModelProperty("总积分") + private BigDecimal points; + + @ApiModelProperty("助记码") + private String mnemonic; + + + @ApiModelProperty("最大购买商品量") + private Integer buy_limit; + + @ApiModelProperty("品牌名称") + private String brand_name; + + @ApiModelProperty("标签") + private String tags; + + @ApiModelProperty("辅助属性") + private List product_assist; + + @ApiModelProperty("规格(JSON)-规格、规格值、goods_id 规格不需要全选就可以添加对应数据[") + private List product_spec; + + @ApiModelProperty("商品卖点特征") + private String product_value; + + @ApiModelProperty("商品视频") + private String product_video; + + @ApiModelProperty("产品描述") + private String product_desc; + + @ApiModelProperty("商品图片库") + private List product_images; + + + @ApiModelProperty("商品详情") + private List promotion_detail; +} diff --git a/client/src/main/java/com/small/client/dto/SxSyncCategory.java b/client/src/main/java/com/small/client/dto/SxSyncCategory.java new file mode 100644 index 00000000..40e24a9d --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SxSyncCategory.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.small.client.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 思迅同步的商品分类表 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@ApiModel(value = "商品分类表", description = "商品分类表") +public class SxSyncCategory implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "店铺Id") + private String store_id; + + @ApiModelProperty(value = "分类编码") + private String item_clsno; + + @ApiModelProperty(value = "分类名称") + private String item_clsname; + + @ApiModelProperty(value = "父类编号") + private String cls_parent; + + @ApiModelProperty(value = "分类排序") + private Integer item_order; + + @ApiModelProperty(value = "是否显示:1-前台显示 0-前台不显示") + private Integer display_flag; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "同步时间戳") + private Long sync_time; + + @ApiModelProperty(value = "新增时间") + private Date created_at; + + @ApiModelProperty(value = "更新时间") + private Date updated_at; + + @ApiModelProperty(value = "子节点") + List children; +} diff --git a/client/src/main/java/com/small/client/dto/SxSyncGoods.java b/client/src/main/java/com/small/client/dto/SxSyncGoods.java new file mode 100644 index 00000000..ff437912 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SxSyncGoods.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.small.client.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 思迅同步的商品表 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@ApiModel(value = "商品信息表", description = "商品信息表") +public class SxSyncGoods implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "店铺Id") + private String store_id; + + @ApiModelProperty(value = "商品编号") + private String item_no; + + @ApiModelProperty(value = "商品名称") + private String item_subname; + + @ApiModelProperty(value = "商品条码") + private String item_subno; + + @ApiModelProperty(value = "小分类编号") + private String item_clsno; + + @ApiModelProperty(value = "大分类名称") + private String big_cls_name; + + @ApiModelProperty(value = "小分类名称") + private String small_cls_name; + + @ApiModelProperty(value = "规格") + private String item_size; + + @ApiModelProperty(value = "单位") + private String unit_no; + + @ApiModelProperty(value = "库存") + private BigDecimal stock; + + @ApiModelProperty(value = "毛利率") + private BigDecimal gross_margin; + + @ApiModelProperty(value = "进货价") + private BigDecimal price; + + @ApiModelProperty(value = "零售价") + private BigDecimal sale_price; + + @ApiModelProperty(value = "会员价") + private BigDecimal vip_price; + + @ApiModelProperty(value = "允许积分") + private BigDecimal vip_acc_flag; + + @ApiModelProperty(value = "积分值") + private BigDecimal vip_acc_num; + + @ApiModelProperty(value = "商品状态") + private Integer sale_flag; + + @ApiModelProperty(value = "品牌名称") + private String item_brand_name; + + @ApiModelProperty(value = "商品助记号") + private String item_rem; + + @ApiModelProperty(value = "生产日期") + private String build_date; + + @ApiModelProperty(value = "质保期") + private String valid_days; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "同步时间戳") + private Long sync_time; + + @ApiModelProperty(value = "同步备注") + private String remark; + + @ApiModelProperty(value = "新增时间") + private Date created_at; + + @ApiModelProperty(value = "更新时间") + private Date updated_at; + + @ApiModelProperty(value = "品牌") + private String itemBrand; + +} + diff --git a/client/src/main/java/com/small/client/dto/SxSyncVip.java b/client/src/main/java/com/small/client/dto/SxSyncVip.java new file mode 100644 index 00000000..ff2d1fb4 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SxSyncVip.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.small.client.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 思迅同步的商品表 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@ApiModel(value = "会员表", description = "会员表") +public class SxSyncVip implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "店铺Id") + private String store_id; + + @ApiModelProperty(value = "会员名称") + private String vip_name; + + @ApiModelProperty(value = "手机号") + private String mobile; + + @ApiModelProperty(value = "会员性别") + private String vip_sex; + + @ApiModelProperty(value = "会员生日") + private String birthday; + + @ApiModelProperty(value = "会员卡号(唯一键)") + private String card_no; + + @ApiModelProperty(value = "会员等级") + private String card_type; + + @ApiModelProperty(value = "储值余额") + private BigDecimal residual_amt; + + @ApiModelProperty(value = "会员积分") + private BigDecimal now_acc_num; + + @ApiModelProperty(value = "加入时间") + private String vip_date; + + @ApiModelProperty(value = "会员状态") + private Integer card_status; + + @ApiModelProperty(value = "同步时间") + private Long sync_time; + + @ApiModelProperty(value = "状态") + private Integer status; + + @ApiModelProperty(value = "新增时间") + private Date created_at; + + @ApiModelProperty(value = "更新时间") + private Date updated_at; +} diff --git a/client/src/main/java/com/small/client/dto/SyncGoodsSearchModel.java b/client/src/main/java/com/small/client/dto/SyncGoodsSearchModel.java new file mode 100644 index 00000000..67f03145 --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SyncGoodsSearchModel.java @@ -0,0 +1,22 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class SyncGoodsSearchModel implements Serializable { + + @ApiModelProperty(value = "分类名称") + private String categoryName;//分类名称 + + @ApiModelProperty(value = "同步分类编号") + private String itemClsno; + + @ApiModelProperty(value = "操作时间") + private String operDate; + + @ApiModelProperty(value = "01全量,02增量") + private String syncType; +} diff --git a/client/src/main/java/com/small/client/dto/SyncThirdMemberReq.java b/client/src/main/java/com/small/client/dto/SyncThirdMemberReq.java new file mode 100644 index 00000000..41e500cd --- /dev/null +++ b/client/src/main/java/com/small/client/dto/SyncThirdMemberReq.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.small.client.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +@ApiModel(description = "第三方会员同步请求参数") +public class SyncThirdMemberReq{ + private static final long serialVersionUID = 1L; + + @ApiModelProperty("会员手机号") + private String user_mobile; + @ApiModelProperty("会员昵称") + private String user_nickname; + @ApiModelProperty("会员真实姓名") + private String user_realname; + @ApiModelProperty("会员性别:1-男;2-女;") + private Integer user_gender; + @ApiModelProperty("会员生日 yyyy-MM-dd") + private String user_birthday; + @ApiModelProperty("会员等级:v1...v9") + private String user_level; + @ApiModelProperty("会员卡号") + private String user_level_card; + @ApiModelProperty("会员积分值") + private BigDecimal user_points; + @ApiModelProperty("会员余额") + private BigDecimal user_money; + @ApiModelProperty("加入时间") + private Date join_time; + @ApiModelProperty("秒级别时间戳") + private Long time_stamp; + @ApiModelProperty("随机字符串") + private String nonce_str; +} diff --git a/client/src/main/java/com/small/client/dto/UploadModel.java b/client/src/main/java/com/small/client/dto/UploadModel.java new file mode 100644 index 00000000..8a1c967f --- /dev/null +++ b/client/src/main/java/com/small/client/dto/UploadModel.java @@ -0,0 +1,15 @@ +package com.small.client.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class UploadModel extends CommentModel{ + @ApiModelProperty("页数作为路径") + private String page; + @ApiModelProperty("同步类型1商品,2分类,3品牌,4会员") + private String syncType; + +} diff --git a/client/src/main/java/com/small/client/enums/DicEnum.java b/client/src/main/java/com/small/client/enums/DicEnum.java new file mode 100644 index 00000000..514156cd --- /dev/null +++ b/client/src/main/java/com/small/client/enums/DicEnum.java @@ -0,0 +1,72 @@ +package com.small.client.enums; + + + +public enum DicEnum { + + SYNCTYPE_01("01","全量","syncType","同步类型","全量同步"), + SYNCTYPE_02("02","增量","syncType","同步类型","增量同步"), + + MUAL_1("1","商品","mual","商品","全量同步"), + MUAL_2("2","分类","mual","分类","分类"), + MUAL_3("3","品牌","mual","品牌","品牌"), + MUAL_4("4","会员","mual","会员","会员"), + ; + private String code; + + private String value; + + private String dicType; + + private String dicName; + + private String desc; + + DicEnum(String code, String value, String dicType, String dicName, String desc) { + this.code = code; + this.value = value; + this.dicType = dicType; + this.dicName = dicName; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getDicType() { + return dicType; + } + + public void setDicType(String dicType) { + this.dicType = dicType; + } + + public String getDicName() { + return dicName; + } + + public void setDicName(String dicName) { + this.dicName = dicName; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/client/src/main/java/com/small/client/service/SxDataAbst/SxDataAbstService.java b/client/src/main/java/com/small/client/service/SxDataAbst/SxDataAbstService.java new file mode 100644 index 00000000..6b1e5284 --- /dev/null +++ b/client/src/main/java/com/small/client/service/SxDataAbst/SxDataAbstService.java @@ -0,0 +1,180 @@ +package com.small.client.service.SxDataAbst; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import com.small.client.Cache.CommonCache; +import com.small.client.dao.SxDataDao; +import com.small.client.dto.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public abstract class SxDataAbstService { + @Autowired + private CommonCache commonCache; + + /** + * List 转换为 List + * @param sxSyncVipList + * @return + */ + public List ConverList(List sxSyncVipList){ + List syncThirdMemberReqList=new ArrayList<>(); + if(CollUtil.isNotEmpty(sxSyncVipList)){ + SyncThirdMemberReq syncThirdMemberReq=null; + for (SxSyncVip sxSyncVip : sxSyncVipList) { + syncThirdMemberReq = new SyncThirdMemberReq(); + syncThirdMemberReq.setUser_nickname(sxSyncVip.getVip_name()); + syncThirdMemberReq.setUser_realname(sxSyncVip.getVip_name()); + if ("男".equals(sxSyncVip.getVip_name())) {//todo 需要确认数据是不是这样判断 + syncThirdMemberReq.setUser_gender(1); + } + if ("男".equals(sxSyncVip.getVip_name())) { + syncThirdMemberReq.setUser_gender(2); + } + syncThirdMemberReq.setUser_mobile(sxSyncVip.getMobile()); + syncThirdMemberReq.setUser_birthday(sxSyncVip.getBirthday()); + syncThirdMemberReq.setUser_level(sxSyncVip.getCard_type());//todo 涉及会员等级字典转换 + syncThirdMemberReq.setUser_level_card(sxSyncVip.getCard_no()); + syncThirdMemberReq.setUser_points(sxSyncVip.getNow_acc_num()); + syncThirdMemberReq.setUser_money(sxSyncVip.getResidual_amt()); + if(sxSyncVip.getVip_date()!=null){ + try { + syncThirdMemberReq.setJoin_time(DateUtils.parseDate(sxSyncVip.getVip_date())); + } catch (ParseException e) { + log.info("时间转换异常{0}",e); + throw new RuntimeException(e); + } + } + syncThirdMemberReqList.add(syncThirdMemberReq); + } + } + return syncThirdMemberReqList; + } + + /** + * + * @param sxSyncCategories + * @param allSxSyncCategories 所有分类 + * @return + */ + public List ConVToSxCategoryModel(List sxSyncCategories,List allSxSyncCategories) { + if(CollectionUtil.isEmpty(sxSyncCategories)){ + return new ArrayList<>(); + } + Iterator iterator= sxSyncCategories.iterator(); + List sxCategoryModels=new ArrayList<>(); + SxCategoryModel sxCategoryModel=null; + while (iterator.hasNext()){ + SxSyncCategory sxSyncCategory= iterator.next(); + sxCategoryModel=new SxCategoryModel(); + sxCategoryModel.setCategory_image(SxDataDao.DEFAULT_IMG); + sxCategoryModel.setCategory_name(sxSyncCategory.getItem_clsname()); + //寻找父级 + if(null!=sxSyncCategory.getCls_parent()){ + SxSyncCategory firstNode=getParentNode(allSxSyncCategories,sxSyncCategory.getCls_parent()); + sxCategoryModel.setParent_name(firstNode.getItem_clsname());//todo 暂时无用 + //如何存在上级的上级,则上级为第二层,上上及为第一层 + if(null!=firstNode.getCls_parent()) {//还存在上级 + SxSyncCategory secondNode=getParentNode(allSxSyncCategories,sxSyncCategory.getCls_parent()); + sxCategoryModel.setFirst_category_name(secondNode.getItem_clsname()); + sxCategoryModel.setSecond_category_name(firstNode.getItem_clsname()); + }else { + sxCategoryModel.setFirst_category_name(firstNode.getItem_clsname()); + } + } + sxCategoryModels.add(sxCategoryModel); + } + return sxCategoryModels; + } + + /** + * 通过流查找父节点 + * @param sxSyncCategories + * @param parentId + */ + private SxSyncCategory getParentNode(List sxSyncCategories,String parentId){ + List list= sxSyncCategories.stream().filter(cc-> + cc.getItem_clsno().trim().equals(parentId.trim())) + .collect(Collectors.toList()); + return CollectionUtil.isNotEmpty(list)?list.get(0):new SxSyncCategory(); + } + + /** + * 将List转换为List + * @param sxSyncGoods + * @return + */ + public List CvtToGoosModel(List sxSyncGoods,List specPriceDtoList){ + if(CollectionUtil.isEmpty(sxSyncGoods)){ + return null; + } + List sxGoosModelList=new ArrayList<>(); + SxGoosModel sxGoosModel=null; + for (SxSyncGoods sxSyncGood:sxSyncGoods){ + sxGoosModel=new SxGoosModel(); + sxGoosModel.setProduct_name(sxSyncGood.getItem_subname()); + sxGoosModel.setProduct_number(sxSyncGood.getItem_no().trim());// todo + sxGoosModel.setProduct_barcode(sxSyncGood.getItem_subno());// todo + + sxGoosModel.setFirst_category_name(commonCache.get(sxSyncGood.getSmall_cls_name()));// todo + sxGoosModel.setSecond_category_name("");// todo + + sxGoosModel.setThree_category_name("");// todo + sxGoosModel.setProduct_type("");// todo + sxGoosModel.setProduct_kind("");// todo + sxGoosModel.setCost_price(sxSyncGood.getPrice());//成本价 todo + sxGoosModel.setOriginal_price(sxSyncGood.getSale_price());//原价 todo + sxGoosModel.setPrice(sxSyncGood.getSale_price());// + sxGoosModel.setMember_price(sxSyncGood.getVip_price());//会员价 + sxGoosModel.setStock(sxSyncGood.getStock());//库存 todo + sxGoosModel.setGross_margin(sxSyncGood.getGross_margin()); //毛利率 todo + sxGoosModel.setUnit(sxSyncGood.getUnit_no());//单位 + sxGoosModel.setCan_piont(new BigDecimal(0));//可用积分 todo + sxGoosModel.setPoints(sxSyncGood.getVip_acc_num());//总积分 todo + sxGoosModel.setMnemonic(sxSyncGood.getItem_rem());//助记码 todo + sxGoosModel.setRetail_price(sxSyncGood.getSale_price()); + // sxGoosModel.setBuy_limit(10);//最大购买商品量 todo + sxGoosModel.setBrand_name(commonCache.get(sxSyncGood.getItemBrand()));//品牌 todo + sxGoosModel.setTags("");//标签 todo + + sxGoosModel.setProduct_assist(Arrays.asList(sxSyncGood.getItem_subname()));//帮助 todo + + sxGoosModel.setProduct_spec(Collections.singletonList(sxSyncGood.getItem_size()==null?"":sxSyncGood.getItem_size()));//规格 + + sxGoosModel.setProduct_value("");//商品卖点特征 todo + + sxGoosModel.setProduct_video("");//商品视频 todo + + sxGoosModel.setProduct_desc("");//商品描述 todo + + sxGoosModel.setProduct_images(new ArrayList<>());//介绍图片 todo + + sxGoosModel.setPromotion_detail(new ArrayList<>());//活动列表 todo + + SxGoosModel finalSxGoosModel = sxGoosModel; + specPriceDtoList.forEach(m->{ + if(sxSyncGood.getItem_no().equals(m.getItemNo())){ + String type=m.getDiscountType(); + if(type.equals("1")){ + finalSxGoosModel.setPrice(m.getSpecPrice()); + finalSxGoosModel.setBuy_limit(m.getSaleQty());//最大购买商品量 todo + } + if(type.equals("2")){ + finalSxGoosModel.setPrice(finalSxGoosModel.getPrice().multiply(m.getDiscount())); + } + } + }); + sxGoosModelList.add(sxGoosModel); + } + return sxGoosModelList; + } +} diff --git a/client/src/main/java/com/small/client/service/SxDataService.java b/client/src/main/java/com/small/client/service/SxDataService.java new file mode 100644 index 00000000..3c3cc48d --- /dev/null +++ b/client/src/main/java/com/small/client/service/SxDataService.java @@ -0,0 +1,53 @@ +package com.small.client.service; + + +import com.small.client.dto.*; + + +public interface SxDataService { + + /** + * 同步商品分类数据 + * @param dataBaseInfo + * @param commentModel + */ + void SyncCategory(DataBaseInfo dataBaseInfo, CommentModel commentModel); + + /** + * 同步商品数据 + * @param dataBaseInfo + * @param commentModel + */ + void SyncGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel); + + /** + * 品牌同步 + * @param dataBaseInfo + * @return + */ + void SyncBranchList(DataBaseInfo dataBaseInfo, CommentModel commentModel); + + /** + * 同步会员数据 + * @param dataBaseInfo + */ + void SyncVipList(DataBaseInfo dataBaseInfo, CommentModel commentModel); + + + CommentModel getCommentModel(); + + void getAppSign(); + + String downLoadClient(); + + void checkForUpdates(); + + /** + * 获取服务器配置 + * @param commentModel + * @return + */ + DataBaseInfo getDataBaseInfo(CommentModel commentModel); + + +} diff --git a/client/src/main/java/com/small/client/service/WebClientService.java b/client/src/main/java/com/small/client/service/WebClientService.java new file mode 100644 index 00000000..b94a63dc --- /dev/null +++ b/client/src/main/java/com/small/client/service/WebClientService.java @@ -0,0 +1,88 @@ +package com.small.client.service; + +import cn.hutool.json.JSONObject; +import com.small.client.Utils.FileUtils; +import com.small.client.Utils.HttpUtils; +import com.small.client.dto.CommentModel; +import com.small.client.dto.UploadModel; +import lombok.extern.slf4j.Slf4j; +import netscape.javascript.JSObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +@Service +@Slf4j +@Component +public class WebClientService { + @Value("${remoteIp}") + private String remoteIp; + + private final RestTemplate restTemplate; + + public WebClientService(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public String get(String url) { + return restTemplate.getForObject(url, String.class); + } + + /** + * 文件上传 + */ + public String uploudSxData(String filePath, CommentModel commentModel,String page,String syncType){ + UploadModel uploadModel=new UploadModel(); + uploadModel.setAppKey(commentModel.getAppKey()); + uploadModel.setSign(commentModel.getSign()); + uploadModel.setPage(page); + uploadModel.setSyncType(syncType); + //"C:\\Users\\Administrator\\uploaded\\2025\\3\\25\\goods_1.txt" + return this.uploadFile(filePath, remoteIp+HttpUtils.URL_UPLOUP,uploadModel); + } + + + public String uploadFile(String filePath, String url, UploadModel uploadModel) { + // 创建MultiValueMap来封装文件数据和请求参数(如果有的话) + MultiValueMap body = new LinkedMultiValueMap<>(); + FileSystemResource file = new FileSystemResource(filePath); // 文件路径 + body.add("file", file); // "file"是与服务器期望的表单字段名称相对应的键,例如在Spring Controller中用@RequestParam("file") String file接收文件数据 + body.add("appKey",uploadModel.getAppKey()); + body.add("sign",uploadModel.getSign()); + body.add("page",uploadModel.getPage());//页数 + body.add("syncType",uploadModel.getSyncType());//商品类型 + // 设置请求头,指定为multipart/form-data类型,并设置boundary(可选) + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + // 创建HttpEntity对象,它将用于POST请求体中包含文件数据和请求头信息 + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + // 执行POST请求进行文件上传 + JSONObject jsonObject= restTemplate.exchange(url, HttpMethod.POST, requestEntity, JSONObject.class).getBody(); + log.info(jsonObject.toString()); + log.info(jsonObject.getStr("error_msg")); + log.info(jsonObject.getStr("error_code")); + return jsonObject.getStr("error_code"); + } + + public static void main(String[] args) { + + // String responseStr= new WebClientService(new RestTemplate()).get("http://localhost:8088/mobile/account/login/testcase"); + +// String responseStr= new WebClientService(new RestTemplate()).get("http://localhost:8088/mobile/account/login/testcase"); +// System.out.printf(responseStr); + // new WebClientService(new RestTemplate()).uploudSxData(); + log.info("测试"); + } + +} diff --git a/client/src/main/java/com/small/client/service/imp/SxDataServiceImp.java b/client/src/main/java/com/small/client/service/imp/SxDataServiceImp.java new file mode 100644 index 00000000..1aea50fd --- /dev/null +++ b/client/src/main/java/com/small/client/service/imp/SxDataServiceImp.java @@ -0,0 +1,645 @@ +package com.small.client.service.imp; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.small.client.Cache.CommonCache; +import com.small.client.Utils.*; +import com.small.client.dao.SxDataDao; +import com.small.client.dto.*; +import com.small.client.enums.DicEnum; +import com.small.client.service.SxDataAbst.SxDataAbstService; +import com.small.client.service.SxDataService; + +import com.small.client.service.WebClientService; +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.StreamUtils; +import org.springframework.web.client.RestTemplate; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.*; +import java.util.stream.Collectors; + +import static com.small.client.Utils.FileUtils.copyFile; + + +@Service +@Slf4j +public class SxDataServiceImp extends SxDataAbstService implements SxDataService { + @Autowired + private SxDataDao sxDataDao; + + @Autowired + private RestTemplate restTemplate; + + @Value("${remoteIp}") + private String remoteIp; + + @Autowired + private CommonCache commonCache; + + @Autowired + private WebClientService webClientService; + + + /** + * 同步商品分类数据 + * @param dataBaseInfo + * @param commentModel + */ + @Override + public void SyncCategory(DataBaseInfo dataBaseInfo, CommentModel commentModel) { + dataBaseInfo= getDataBaseInfo(commentModel); + // 记录总数 + Integer total = sxDataDao.getTBdItemClsTotal(dataBaseInfo); + if(total==0){ + log.info("暂无商品分类同步"); + return; + } + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + List allSxSyncCategories= sxDataDao.findTBdItemClsList(dataBaseInfo); + int syncCount =0; + for (int i = 1; i <=pages; i++) { + List sxSyncCategories= sxDataDao.findTBdItemClsListPage(dataBaseInfo,i,SxDataDao.PAGESIZE); + List sxCategoryModelList= ConVToSxCategoryModel(sxSyncCategories,allSxSyncCategories); + JSONArray jsonArray =null; + String jsonString=""; + ObjectMapper objectMapper = new ObjectMapper(); + try { + jsonString = objectMapper.writeValueAsString(sxCategoryModelList); + jsonArray = JSONUtil.parseArray(jsonString); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_CATEGORY + +"?appKey="+commentModel.getAppKey() + +"&sign="+commentModel.getSign(),jsonArray);//todo 后期改为文件传输 + if (!HttpUtils.SUCCESSCODE.equals(code)) { + continue; + } + syncCount+=sxCategoryModelList.size(); + } + log.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount); + } + + /** + * 同步商品数据 + * @param dataBaseInfo + * @param commentModel + */ + @Override + public void SyncGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel) { + //dataBaseInfo= getDataBaseInfo(commentModel); + String syncType ="01"; + if(StringUtils.isNotEmpty(commentModel.getSyncTime())){//如果有同步时间,则为增量 + syncType="02"; + dataBaseInfo.setSyncType("02"); + } + if(StringUtils.isEmpty(syncType)){ + syncType="01"; + dataBaseInfo.setSyncType("01"); + } + switch (syncType) { + case "01"://全量 + syncAllGoods(dataBaseInfo, commentModel); + break; + case "02"://增量 todo test + syncIncrementAddGoods(dataBaseInfo, commentModel); + syncIncrementModifyGoods(dataBaseInfo, commentModel); + syncIncrementStock(dataBaseInfo, commentModel); + break; + } + + } + + /** + * 同步品牌数据 + * @param dataBaseInfo + * @param commentModel + */ + @Override + public void SyncBranchList(DataBaseInfo dataBaseInfo, CommentModel commentModel) { + dataBaseInfo= getDataBaseInfo(commentModel); + List brandModels= sxDataDao.getBdBrandList(dataBaseInfo); + if(brandModels!=null&&brandModels.size()>0){ + String jsonString =""; + JSONArray jsonArray =new JSONArray(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + jsonString = objectMapper.writeValueAsString(brandModels); + jsonArray = JSONUtil.parseArray(jsonString); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_BRAND + +"?appKey="+commentModel.getAppKey() + +"&sign="+commentModel.getSign(),jsonArray);//todo 后期改为文件传输 + if(code!=null){ + log.info("品牌总共有{}条数据,同步完成{}条",brandModels.size(),brandModels.size()); + } + }else { + log.info("品牌数据为空"); + } + + } + + /** + * 同步会员数据 + * @param dataBaseInfo + * @param commentModel + */ + @Override + public void SyncVipList(DataBaseInfo dataBaseInfo, CommentModel commentModel) { + dataBaseInfo= getDataBaseInfo(commentModel); + String where="where 1=1 "; + if(StringUtils.isNotEmpty(commentModel.getSyncTime())){ + where+="and oper_date > '"+commentModel.getSyncTime()+"'"; + } + dataBaseInfo.setWhere(where); + // 记录总数 + Integer total = sxDataDao.getTrmVipInfoTotal(dataBaseInfo); + if(total==0){ + log.info("暂无会员数据同步"); + return; + } + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + List memberList=new ArrayList<>(); + int syncCount =0; + for (int i = 1; i <=pages; i++) { + memberList.clear(); + List sxSyncVipList= sxDataDao.findRmVipInfoListPage(dataBaseInfo,i,SxDataDao.PAGESIZE); + //处理数据转换SxSyncVip>SyncThirdMemberReq + memberList=ConverList(sxSyncVipList); + String jsonString =""; + ObjectMapper objectMapper = new ObjectMapper(); + try { + jsonString = objectMapper.writeValueAsString(memberList); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_MEMBER + +"?appKey="+commentModel.getAppKey() + +"&sign="+commentModel.getSign(),memberList);//todo 后期改为文件传输 + if (!HttpUtils.SUCCESSCODE.equals(code)) { + continue; + } + syncCount+=memberList.size(); + } + log.info("vip会员总共有{}条数据,同步完成{}条",total,syncCount); + } + + /** + * 获取并缓存父节点的根节点,用户查找数据 + * @param dataBaseInfo + * @param parentName + */ + public String getAndCacheTree(DataBaseInfo dataBaseInfo,String parentName){ + List sxSyncCategories=new SxDataDao().findTBdItemClsList(dataBaseInfo); + String parentId= sxSyncCategories.stream().filter(m->m.getItem_clsname().equals(parentName)). + map(SxSyncCategory::getItem_clsno).collect(Collectors.joining()); + getBdBrandCacheList(dataBaseInfo); + String childrens=commonCache.get(CommonCache.CACHE_CATEGROY+parentId); + if(childrens==null){ + log.info(JSONUtil.toJsonStr(buildTree(sxSyncCategories,parentId))); + } + return parentId; + } + + /** + * 构建树节点 + * @param sxSyncCategories + * @return + */ + public List buildTree(List sxSyncCategories,String parentId){ + List treeNodes=new ArrayList<>(); + List rootSxSyncCategory=getRootNode(sxSyncCategories); + for (SxSyncCategory node : rootSxSyncCategory) { + node=buildChildTree(node,sxSyncCategories,parentId); + treeNodes.add(node); + } + return treeNodes; + } + + /** + * 获取所有的根节点 + * @param sxSyncCategories + * @return + */ + public List getRootNode(List sxSyncCategories){ + List rootNodeList=new ArrayList<>(); + for (SxSyncCategory node : sxSyncCategories) { + if (null==node.getCls_parent()) { + rootNodeList.add(node); + } + } + return rootNodeList; + } + + /** + * 构建子节点 + * @param root + * @param sxSyncCategories + * @return + */ + public SxSyncCategory buildChildTree(SxSyncCategory root,List sxSyncCategories,String findByParentId) { + List children = new ArrayList<>(); + for (SxSyncCategory node : sxSyncCategories) { + commonCache.put(node.getItem_clsno(),node.getItem_clsname());//把数据加入缓存 + if (root.getItem_clsno().equals(node.getCls_parent())) { + children.add(buildChildTree(node,sxSyncCategories,findByParentId)); + } + } + if(root.getItem_clsno().equals(findByParentId)){ + commonCache.put(CommonCache.CACHE_CATEGROY+findByParentId,children.stream().map(SxSyncCategory::getItem_clsno).collect(Collectors.joining(","))); + } + root.setChildren(children); + return root; + } + + /** + *同步所有商品 + * @param dataBaseInfo + * @param commentModel + */ + private void syncAllGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){ + String where="where 1=1"; + Integer total =0; + if(DicEnum.SYNCTYPE_02.getCode().equals(dataBaseInfo.getSyncType())){ + if (StringUtils.isNotEmpty(dataBaseInfo.getCategoryName())) { + String parentId=getAndCacheTree(dataBaseInfo,dataBaseInfo.getCategoryName()); + String childrens= commonCache.get(CommonCache.CACHE_CATEGROY+parentId); + //syncGoodsSearchModel.setItemClsno(childrens); + where += " and b.item_clsno in ('" + childrens + "')"; + } + if(StringUtils.isNotEmpty(commentModel.getSyncTime())){ + where+=" and b.modify_date>'"+commentModel.getSyncTime()+"' "; + where+=" or b.build_date>'"+commentModel.getSyncTime()+"' "; + } + if(StringUtils.isNotEmpty(dataBaseInfo.getOperDate())){ + where+=" and t.oper_date>'"+dataBaseInfo.getOperDate()+"' "; + } + dataBaseInfo.setWhere(where); + // 记录总数 + total = sxDataDao.getTBditemInfoJoninTotal(dataBaseInfo); + }else { + dataBaseInfo.setWhere(where); + total = sxDataDao.getTBditemInfoTotal(dataBaseInfo); + } + if(total==0){ + log.info("暂无商品同步"); + return; + } + + // 总页数 + int pages = CommonUtil.getPagesCount(total, SxDataDao.PAGESIZE); + int syncCount =0; + + List discountList= getDiscountFromCache(dataBaseInfo); + List specPriceDtoList= getSpecPriceFromCache(dataBaseInfo); + specPriceDtoList.addAll(discountList); + + List folders=new ArrayList<>(); + for (int i = 1; i <=pages; i++) { + List sxSyncGoods= sxDataDao.findBditemInfoListPage(dataBaseInfo,i,SxDataDao.PAGESIZE); + List sxGoosModelList= CvtToGoosModel(sxSyncGoods,specPriceDtoList); + String jsonString=""; + ObjectMapper objectMapper = new ObjectMapper(); + try { + jsonString = objectMapper.writeValueAsString(sxGoosModelList); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + String code= writeToFileAndUploud(i,jsonString,commentModel,DicEnum.MUAL_1.getCode()); + if (!HttpUtils.SUCCESSCODE.equals(code)) { + continue; + } + folders.add(String.valueOf(i)); + syncCount+=sxSyncGoods.size(); + } + // folders.add(String.valueOf(2)); + //folders.add(String.valueOf(4)); + //folders.add(String.valueOf(5)); + log.info("商品分类总共有{}条数据,同步完成{}条",total,syncCount); + String code= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_GOODS_READ + +"?appKey="+commentModel.getAppKey() + +"&sign="+commentModel.getSign() + +"&syncType="+DicEnum.MUAL_1.getCode(), + JSONUtil.parseArray(folders)); + if (HttpUtils.SUCCESSCODE.equals(code)) { + log.info("思迅商品同步完成,通知服务器处理数据相应成功"); + //记录同步时间 + createDateFile(); + } + } + + /** + * 文件上传到服务器 + * @param page + * @param content + * @param commentModel + * @return + */ + private String writeToFileAndUploud(Integer page,String content,CommentModel commentModel,String syncType){ + FileUtils fileUtils= new FileUtils(); + File file=fileUtils.createFile(syncType,page); + String fileName=fileUtils.getFileName(syncType,page,FileUtils.txtEnd); + String filePath=file.getAbsolutePath(); + fileUtils.writeFile(filePath,fileName,content); + return webClientService.uploudSxData(filePath+FileUtils.pathSeparator+fileName,commentModel,page.toString(),syncType); + } + + /** + * 记录同步时间 + */ + private void createDateFile(){ + String path=JarPathUtil.getRuntimePath(); + FileUtils fileUtils= new FileUtils(); + File file=fileUtils.createFile(path); + String filePath=file.getAbsolutePath(); + String date= DateUtil.format(new Date(),"yyyy-MM-dd"); + fileUtils.writeFile(filePath,FileUtils.REFLESHDATE,date); + } + + /** + * 增量新增数据,新增商品数据 + * @param dataBaseInfo + * @param commentModel + */ + private void syncIncrementAddGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){ + syncAllGoods(dataBaseInfo,commentModel); + } + + /** + * 增量同步 商品内容变化 + * @param dataBaseInfo + * @param commentModel + */ + private void syncIncrementModifyGoods(DataBaseInfo dataBaseInfo, CommentModel commentModel){ + syncAllGoods(dataBaseInfo,commentModel); + } + + /** + * 增量同步 库存变化 + */ + private void syncIncrementStock(DataBaseInfo dataBaseInfo, CommentModel commentModel){ + dataBaseInfo.setOperDate(commentModel.getSyncTime()); + commentModel.setSyncTime(""); + syncAllGoods(dataBaseInfo,commentModel); + } + + /** + *获取特价商品 + * @param dataBaseInfo + * @return + */ + public List getDiscountFromCache(DataBaseInfo dataBaseInfo){ + List specPriceDtos= commonCache.getSpecPrice("specDiscountCache"); + if (null!=specPriceDtos){ + return specPriceDtos; + }else { + specPriceDtos= sxDataDao.getSpecPriceList(dataBaseInfo); + commonCache.putSpecPrice("specDiscountCache",specPriceDtos); + } + return specPriceDtos; + } + + + /** + *获取促销产品数据 + * @param dataBaseInfo + * @return + */ + public List getSpecPriceFromCache(DataBaseInfo dataBaseInfo){ + List specPriceDtos= commonCache.getSpecPrice("specPriceCache"); + if(null!=specPriceDtos){ + return specPriceDtos; + }else { + specPriceDtos= sxDataDao.getDiscountPriceList(dataBaseInfo); + commonCache.putSpecPrice("specDiscountCache",specPriceDtos); + } + return specPriceDtos; + } + + /** + * 获取品牌数据并加入到缓存 + * @param dataBaseInfo + * @return + */ + public void getBdBrandCacheList(DataBaseInfo dataBaseInfo){ + List specPriceDtos= commonCache.getBrandCahce("brandCache"); + if(null==specPriceDtos){ + specPriceDtos= sxDataDao.getBdBrandList(dataBaseInfo); + if(CollectionUtil.isNotEmpty(specPriceDtos)){ + for (BrandModel brandModel : specPriceDtos) { + commonCache.put(brandModel.getCodeId(),brandModel.getBrand_name()); + } + commonCache.setBrandCahce("brandCache",specPriceDtos); + } + + } + } + + @Override + public CommentModel getCommentModel() { + String path=JarPathUtil.getRuntimePath(); + log.info(JarPathUtil.getRuntimePath()); + File folder = new File(path); + //读取文件 + try { + String encryptedData = getPrimaryKey(); + Map result= CryptoUtils.decryptAndUnpack(encryptedData); + CommentModel commentModel=new CommentModel(); + commentModel.setSign(result.get("sign")); + commentModel.setAppKey(result.get("appKey")); + commentModel.setStoreId(result.get("storeId")); + //获取上次同步的最大时间 + File[] lastDateJsonFile = folder.listFiles((dir, name) -> name.endsWith(FileUtils.REFLESHDATE)); + if(lastDateJsonFile!=null&&lastDateJsonFile.length>0){ + String lastDate = new String(Files.readAllBytes(lastDateJsonFile[0].toPath()), StandardCharsets.UTF_8).trim(); + commentModel.setSyncTime(lastDate); + } + return commentModel; + } catch (RuntimeException | IOException e) { + throw new RuntimeException("密钥获取失败"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void getAppSign() { + String encryptedData= getPrimaryKey(); + JSONObject jsonObject=new JSONObject(); + jsonObject.putOnce("primaryKey",encryptedData); + String primaryKey= HttpUtils.postData(restTemplate,remoteIp+HttpUtils.URL_SYNC_GET_APPSIGN + +"?primaryKey="+encryptedData, jsonObject,"primaryKey"); + if(null!=primaryKey){ + String path=JarPathUtil.getRuntimePath(); + FileUtils fileUtils= new FileUtils(); + File file=fileUtils.createFile(path); + String filePath=file.getAbsolutePath(); + fileUtils.writeFile(filePath,FileUtils.PRIMARYKEY,primaryKey); + }else { + log.info("获取服务器密钥失败"); + } + } + + + /** + * 获取文本密钥 + * @return + */ + private String getPrimaryKey(){ + String path=JarPathUtil.getRuntimePath(); + log.info("RuntimePath:{}",JarPathUtil.getRuntimePath()); + File folder = new File(path); + File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(FileUtils.PRIMARYKEY)); + if(null!=jsonFiles&&jsonFiles.length>0){ + try { + return new String(Files.readAllBytes(jsonFiles[0].toPath()), StandardCharsets.UTF_8); + }catch (RuntimeException | IOException e){ + throw new RuntimeException("读取[fileName]文件错误"); + } + + } + return null; + } + + @Override + public String downLoadClient() { + String downloadDirectory=FileUtils.CLIENTSTALLPATH; + String originalFileName = ""; + try { + File file= new File(downloadDirectory); + if(!file.exists()){ + file.mkdirs(); // 确保目录存在 + } + log.info("文件下载目录: {}", downloadDirectory); + HttpHeaders headers = new HttpHeaders(); + HttpEntity requestEntity = new HttpEntity<>(headers); + String encryptedData = getPrimaryKey(); + + ResponseEntity response = restTemplate.exchange( + remoteIp+HttpUtils.URL_SYNC_GET_DOWNCLIENTJAR+"?primaryKey="+encryptedData, + HttpMethod.GET, + requestEntity, + Resource.class); + if(response.getStatusCode().is2xxSuccessful() && null!= response.getHeaders().getFirst("error")){ + String error=response.getHeaders().getFirst("error"); + switch (Objects.requireNonNull(error)){ + case "noVersion": + log.info("没有版本更新"); + break; + case "noFile": + log.info("系统错误:文件不存在"); + break; + case "500":; + log.info("系统错误:系统内部错误"); + break; + case "noValid": + log.info("密钥校验失败:密钥过期"); + break; + } + return null; + } + if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { + // 从Content-Disposition头获取文件名 + String contentDisposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION); + if (contentDisposition != null && contentDisposition.contains("filename=")) { + originalFileName = contentDisposition + .split("filename=")[1] + .replace("\"", ""); // 去除引号 + } + // 如果无法从header获取,使用默认名 + if (originalFileName == null || originalFileName.isEmpty()) { + originalFileName = "new_client" + System.currentTimeMillis()+".jar"; + } + File outputFile = new File(downloadDirectory + originalFileName); + try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { + StreamUtils.copy(response.getBody().getInputStream(), outputStream); + log.info("文件下载成功: {}" , outputFile.getAbsolutePath()); + }catch (Exception e){ + log.error("下载失败,下载流异常:{}",e.getMessage()); + return null; + } + } else { + log.error("文件下载失败: {}", response.getStatusCode()); + return null; + } + }catch (Exception e){ + log.error("文件下载失败:{}",e.getMessage()); + return null; + } + return downloadDirectory+originalFileName; + } + + @Override + public void checkForUpdates() { + log.info("curentPath:{}",JarPathUtil.getRuntimePath()); + File classDirFile = new File(JarPathUtil.getRuntimePath()); + File parentDir = classDirFile.getParentFile(); + String filePath= this.downLoadClient(); + if (filePath != null) { + copyFile(filePath,parentDir.getAbsolutePath()+"/lib"); + applyUpdate(); + } + } + + private void applyUpdate() { + try { + File classDirFile = new File(JarPathUtil.getRuntimePath()); + File parentDir = classDirFile.getParentFile(); + // 执行脚本并退出当前应用 + log.info(parentDir.getAbsolutePath()+"/bin/run.bat"); + Runtime.getRuntime().exec(parentDir.getAbsolutePath()+"/bin/run.bat"); + log.info(parentDir.getAbsolutePath()+"/bin/run.bat"); + System.exit(0); + } catch (IOException e) { + log.error("异常{}", e.getMessage()); + } + } + + + @Override + public DataBaseInfo getDataBaseInfo(CommentModel commentModel) { + JSONObject jsonObject=new JSONObject(); + jsonObject.putOnce("appKey",commentModel.getAppKey()); + jsonObject.putOnce("sign",commentModel.getSign()); + StoreDbConfig storeDbConfig= HttpUtils.postDataGetConfig(restTemplate,remoteIp+HttpUtils.URL_SYNC_GET_STOREdBCONFIG + +"?appKey="+commentModel.getAppKey() + +"&sign="+commentModel.getSign(), jsonObject); + DataBaseInfo dataBaseInfo=new DataBaseInfo(); + if(null!=storeDbConfig){ + dataBaseInfo.setIp(storeDbConfig.getDbIp()); + dataBaseInfo.setPassword(storeDbConfig.getDbPassword()); + dataBaseInfo.setDataBaseName(storeDbConfig.getDbName()); + dataBaseInfo.setDbPort(storeDbConfig.getDbPort()); + dataBaseInfo.setSyncMode(storeDbConfig.getSyncMode()); + dataBaseInfo.setCronExpression(storeDbConfig.getCronExpression()); + dataBaseInfo.setCategoryName(storeDbConfig.getCategoryName()); + return dataBaseInfo; + } + return new DataBaseInfo(); + } + +} diff --git a/client/src/main/resources/application.yml b/client/src/main/resources/application.yml new file mode 100644 index 00000000..6b48c137 --- /dev/null +++ b/client/src/main/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 9099 + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + +#配置远程模板信息 +#服务器地址 +logging: + charset: + console: UTF-8 + +remoteIp: https://mall.gpxscs.cn \ No newline at end of file diff --git a/client/src/main/resources/logback.xml b/client/src/main/resources/logback.xml new file mode 100644 index 00000000..79a5a80e --- /dev/null +++ b/client/src/main/resources/logback.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + UTF-8 + %d{yyyy-MM-dd HH:mm:ss} - %msg%n + + + + + + From 46af45ebd93d3f25cd50d023603a1c55de2dc0ed Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Tue, 20 May 2025 18:09:38 +0800 Subject: [PATCH 36/39] =?UTF-8?q?=E8=BF=98=E5=8E=9F=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/ShopBaseProductTypeServiceImpl.java | 4 +-- .../mall/shop/config/GlobalCorsConfig.java | 30 ------------------- .../suisung/mall/shop/config/WebConfig.java | 11 ------- 3 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/config/GlobalCorsConfig.java diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java index bd1ca3d1..82ab1afa 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java @@ -85,8 +85,8 @@ public class ShopBaseProductTypeServiceImpl extends BaseServiceImpl Date: Tue, 20 May 2025 18:49:34 +0800 Subject: [PATCH 37/39] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mall-shop/src/main/resources/bootstrap-dev.yml | 3 +++ mall-shop/src/main/resources/bootstrap-prod.yml | 6 +++++- mall-shop/src/main/resources/bootstrap-test.yml | 5 ++++- mall-shop/src/main/resources/bootstrap-uat.yml | 5 ++++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index fb7aab8d..ca7f8efe 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -181,3 +181,6 @@ esign: app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7 app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB debug: true +#客户端上传文件地址 +client: + path: E:/data \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 4750e715..e0c242cb 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -214,4 +214,8 @@ esign_prod: app_id: 5111986290 app_secret: 4408a0395464596cf7d33dda5f9c7608 app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApzK8BGqUdq9eufyPieCux2bMuKnXHQXgCT2kVcHqwFW1LqZMxm/npuf94C8XLK481klD15WPTVi5YUrqnXYZpIawbuH1+2bfHnZL4aSdZ+QUvlol2WLigoxlgPU9gFYWj/ykovQKi78myWbrIzaM6VJxB6RSJKBVzxm2v8M93J73S8btT7E/RRBtX+dGP7In0PpTwugsHG/w7NQ/e3budt4FLIobGzZT26GkuQ6k8fme6M+aAWgfmQIEGi+a8HLl8hP21wHHCxLJKHxxH/OADQGnzRiK632yaXmGD9/cj2xo/6zzNKDkHK9Ud64E7Pj2LrZPBaXPoxhLqJ7j6v6MgQIDAQAB - debug: false \ No newline at end of file + debug: false + +#客户端上传文件地址 +client: + path: /home/user/data \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 73384e68..0a13acd5 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -184,4 +184,7 @@ esign: app_id: 7439053575 app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7 app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB - debug: true \ No newline at end of file + debug: true +#客户端上传文件地址 +client: + path: /home/user/data \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 73384e68..0a13acd5 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -184,4 +184,7 @@ esign: app_id: 7439053575 app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7 app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB - debug: true \ No newline at end of file + debug: true +#客户端上传文件地址 +client: + path: /home/user/data \ No newline at end of file From 7cdb9f88f20e2310611fc29579cfb72006a55345 Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Tue, 20 May 2025 18:51:55 +0800 Subject: [PATCH 38/39] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mall-shop/src/main/resources/bootstrap-local.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index cc07f8a6..7dd1406f 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -184,4 +184,4 @@ esign: debug: true #客户端上传文件地址 client: - path: @client.path@ + path: E:/data \ No newline at end of file From ba284b945f4509d490da75ef2d0e8819f16269d5 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 20 May 2025 21:13:30 +0800 Subject: [PATCH 39/39] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=AA=E5=88=AB?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E9=80=9A=E7=9F=A5=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/lakala/LklLedgerMember.java | 4 -- .../service/LklLedgerMemberService.java | 12 ---- .../service/impl/LakalaApiServiceImpl.java | 28 +++++---- .../impl/LklLedgerMemberServiceImpl.java | 57 +------------------ .../impl/LklLedgerReceiverServiceImpl.java | 7 ++- .../lakala/service/impl/LklTkServiceImpl.java | 4 +- .../store/service/ShopMchEntryService.java | 2 +- 7 files changed, 23 insertions(+), 91 deletions(-) diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java index ab48a72f..adbaf357 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklLedgerMember.java @@ -52,10 +52,6 @@ public class LklLedgerMember implements Serializable { private String audit_resp; private String remark; private Long mch_id; - private Integer has_esigned; - private Integer has_apply_split; - private Integer has_receiver; - private Integer has_bind_receiver; private String version; private Date created_at; private Date updated_at; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java index 40a2e042..29bfbda5 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/LklLedgerMemberService.java @@ -54,16 +54,4 @@ public interface LklLedgerMemberService extends IBaseService { */ Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark); - /** - * 更新分账多个状态 - * - * @param merCupNo - * @param mchMobile - * @param hasEsigned - * @param hasApplySplit - * @param hasReceiver - * @param hasBindReceiver - * @return - */ - Boolean updateMulStatus(String merCupNo, String mchMobile, Integer hasEsigned, Integer hasApplySplit, Integer hasReceiver, Integer hasBindReceiver); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 96d66b24..c3d0abd8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -615,22 +615,22 @@ public class LakalaApiServiceImpl implements LakalaApiService { String errMsg = ""; ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class); if (ObjectUtil.isEmpty(response) || response.getStatusCode() != HttpStatus.OK) { - errMsg = "商家入网申请电子合同失败:请求失败"; - shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + errMsg = "申请入网电子合同失败,无响应数据!"; + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_LKL_NOPASS, errMsg); return Pair.of(false, errMsg); } JSONObject respBody = response.getBody(); if (ObjectUtil.isNotEmpty(respBody) && !lklSuccessCode.equals(respBody.getStr("code"))) { - errMsg = "商家入网申请电子合同失败:" + (StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg")); - shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + errMsg = "申请入网电子合同失败," + (StrUtil.isBlank(respBody.getStr("msg")) ? "返回状态有误" : respBody.getStr("msg")); + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_LKL_NOPASS, errMsg); return Pair.of(false, errMsg); } JSONObject respData = respBody.getJSONObject("resp_data"); if (respBody.getJSONObject("resp_data") == null) { - errMsg = "商家入网申请电子合同失败:返回数据有误"; - shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); + errMsg = "申请入网电子合同失败,返回数据有误"; + shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_LKL_NOPASS, errMsg); return Pair.of(false, errMsg); } @@ -646,7 +646,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { record.setResp_body(respBody.toString()); Boolean success = lklLedgerEcService.saveOrUpdateByMchId(record); if (!success) { - errMsg = "商家入网申请电子合同失败:数据保存失败"; + errMsg = "申请入网电子合同失败,数据保存失败"; shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); return Pair.of(false, errMsg); } @@ -794,7 +794,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { log.debug("商户入网电子合同申请回调返回requestbody 参数:{}\n authorization参数:{}\n", requestBody, authorization); - String errMsg = "商户入网电子合同申请回调:"; + String errMsg = "入网电子合同申请回调:"; boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); if (!checkSuccess) { log.error(errMsg + "验签失败"); @@ -812,20 +812,20 @@ public class LakalaApiServiceImpl implements LakalaApiService { String ecNo = paramsJSON.getStr("ecNo"); String ecStatus = paramsJSON.getStr("ecStatus"); // COMPLETED if (ecStatus == null || !ecStatus.equals("COMPLETED")) { - log.debug("商户入网电子合同申请状态尚未签署完成!"); + log.debug("入网电子合同申请未签署完成!"); respData.put("message", "商户入网电子合同尚未签署,请稍候!"); return respData; } if (ecApplyId == null || StrUtil.isBlank(ecNo)) { - log.error("商户入网电子合同申请回调:ecApplyId 为空"); + log.error("入网电子合同申请回调:ecApplyId 为空"); respData.put("message", "ecApplyId 返回空值!"); return respData; } LklLedgerEc lklLedgerEc = lklLedgerEcService.getByApplyId(ecApplyId, "", CommonConstant.Enable); if (lklLedgerEc == null) { - log.error("商户入网电子合同申请回调:找不到对应入网lklLedgerEc电子合同记录"); + log.error("入网电子合同申请回调:找不到对应入网lklLedgerEc电子合同记录"); respData.put("message", "找不到对应入网电子合同记录!"); // throw new ApiException("找不到对应入网电子合同记录!"); return respData; @@ -867,13 +867,11 @@ public class LakalaApiServiceImpl implements LakalaApiService { if (!resultPair.getFirst()) { errMsg += resultPair.getSecond(); log.error(errMsg); - shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_NOPASS, errMsg); - // respData.put("message", errMsg); - // return respData; + shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_LKL_NOPASS, errMsg); throw new ApiException(errMsg); } - shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_LKL_PADDING, errMsg); + shopMchEntryService.updateMerchEntryApprovalByMchId(lklLedgerEc.getMch_id(), "", CommonConstant.MCH_APPR_STA_LKL_PADDING, "已提交进件申请,请等待机构审核!"); respData.put("code", "SUCCESS"); respData.put("message", "操作成功!"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java index 31a0a538..bb354f4c 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerMemberServiceImpl.java @@ -123,60 +123,5 @@ public class LklLedgerMemberServiceImpl extends BaseServiceImpl updateWrapper = new UpdateWrapper<>(); - if (StrUtil.isNotBlank(mchMobile)) { - updateWrapper.eq("contact_mobile", mchMobile); - } - if (StrUtil.isNotBlank(merCupNo)) { - updateWrapper.eq("mer_cup_no", merCupNo); - } - - if (hasEsigned != null && hasEsigned > 0) { - i++; - updateWrapper.set("has_esigned", hasEsigned); - } - if (hasApplySplit != null && hasApplySplit > 0) { - i++; - updateWrapper.set("has_apply_split", hasApplySplit); - } - if (hasReceiver != null && hasReceiver > 0) { - i++; - updateWrapper.set("has_receiver", hasReceiver); - } - if (hasBindReceiver != null && hasBindReceiver > 0) { - i++; - updateWrapper.set("has_bind_receiver", hasBindReceiver); - } - - if (i == 0) { - return false; - } - - return update(updateWrapper); - } catch (Exception e) { - log.error("更新分账商家多个状态失败", e); - return false; - } - } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java index 6e259c24..573a4682 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklLedgerReceiverServiceImpl.java @@ -25,7 +25,9 @@ import com.suisung.mall.shop.lakala.mapper.LklLedgerReceiverMapper; import com.suisung.mall.shop.lakala.service.LakalaApiService; import com.suisung.mall.shop.lakala.service.LklLedgerMemberService; import com.suisung.mall.shop.lakala.service.LklLedgerReceiverService; +import com.suisung.mall.shop.store.service.ShopMchEntryService; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -48,6 +50,9 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl 0; if (success) { // 更新多个状态 - lklLedgerMemberService.updateMulStatus(merCupNo, "", 0, 0, 1, 0); + shopMchEntryService.updateMulStatus("", merCupNo, 0, 0, 1, 0); } return success; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java index 6f0dc4ec..266eed9b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LklTkServiceImpl.java @@ -506,7 +506,7 @@ public class LklTkServiceImpl { ResponseEntity response = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), header, formData, JSONObject.class); if (ObjectUtil.isEmpty(response)) { - return Pair.of(false, "进件失败:进件无返回值"); + return Pair.of(false, "请求进件服务无返回值"); } JSONObject respBody = response.getBody(); @@ -520,7 +520,7 @@ public class LklTkServiceImpl { // 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录 Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchMobile, CommonConstant.Disable2, lklMerInnerNo, lklMerInnerNo, formData.toString(), respBody.toString()); if (!success) { - return Pair.of(false, "提交进件成功,但更新商户号失败!"); + return Pair.of(false, "请求进件成功,但更新商户号失败!"); } } catch (Exception e) { diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index 08932b76..fb83e784 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -198,7 +198,7 @@ public interface ShopMchEntryService { * * @param mchId 商家入驻申请 ID,mchId和mchMobile至少必填一个 * @param mchMobile 商家注册的手机号 mchId和mchMobile至少必填一个 - * @param approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核; + * @param approvalStatus 入驻审批状态:1-已通过;2-未通过;3-待审核;4-未申请过;5-已提交拉卡拉审核;21-拉卡拉审核未通过; * @param approvalRemark 审批备注 * @return */