Compare commits
No commits in common. "4efd79c180f1134a2191875e525e59c4a2154883" and "5fa1877072d5c106f169022961b5974ad80c7235" have entirely different histories.
4efd79c180
...
5fa1877072
@ -260,7 +260,7 @@ public class LoginController extends BaseControllerImpl {
|
||||
return accountUserBaseService.doMerchSmsRegisterAndLogin(userMobile, randKey, verifyCode, cid, osType);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "微信用户一键登录与注册")
|
||||
@ApiOperation(value = "微信用户一键登录和注册")
|
||||
@RequestMapping(value = "/doWxUserRegisterAndLogin", method = RequestMethod.POST)
|
||||
public CommonResult doWxUserRegisterAndLogin(@RequestBody WxUserInfoReq wxUserInfoReq) {
|
||||
return accountUserBaseService.doWxUserRegisterAndLogin(wxUserInfoReq);
|
||||
|
||||
@ -2429,7 +2429,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl<AccountUserBaseM
|
||||
* 根据账号和账号类型获取一条记录
|
||||
*
|
||||
* @param userAccount 用户账号
|
||||
* @param userIsAdmin 用户类型: null or 0-普通用户; 1-管理员; 2-入驻商家;
|
||||
* @param userIsAdmin 用户类型: null-普通用户; 1-管理员; 2-入驻商家;
|
||||
* @return AccountUserBase 用户基础信息,如果未找到则返回null
|
||||
*/
|
||||
public AccountUserBase getByAccountAndType(String userAccount, Integer userIsAdmin) {
|
||||
@ -3019,6 +3019,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl<AccountUserBaseM
|
||||
|
||||
// 检查输入字符是不是包含 sql 注入特征,如果包含不给以通过
|
||||
if (!CommonService.isValidInput(wxUserInfoReq.getPhoneNumber(), wxUserInfoReq.getOpenId())) {
|
||||
// new ApiException(ResultCode.VALIDATE_INPUTS);
|
||||
return CommonResult.failed(ResultCode.VALIDATE_INPUTS);
|
||||
}
|
||||
|
||||
@ -3060,7 +3061,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl<AccountUserBaseM
|
||||
accountUserBase.setRights_group_id("0");// 店铺管理员,店铺 权限
|
||||
|
||||
if (!saveOrUpdate(accountUserBase)) {
|
||||
return CommonResult.failed(_("微信注册账号失败!"));
|
||||
return CommonResult.failed(_("用户注册失败!"));
|
||||
}
|
||||
|
||||
Integer userId = accountUserBase.getUser_id();
|
||||
@ -3152,7 +3153,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl<AccountUserBaseM
|
||||
AccountUserBindConnect accountUserBindConnect = accountUserBindConnectService.getBindByBindId(mobile, BindCode.MOBILE, CommonConstant.USER_TYPE_NORMAL);
|
||||
if (accountUserBindConnect == null || !Objects.equals(accountUserBase.getUser_id(), accountUserBindConnect.getUser_id())) {
|
||||
// 先绑定手机号
|
||||
if (accountUserBindConnectService.bindMobileAndOpenId(wxUserInfoReq, accountUserBase.getUser_id(), CommonConstant.USER_TYPE_NORMAL) == null) {
|
||||
if (accountUserBindConnectService.bindMobileAndOpenId(wxUserInfoReq, accountUserBase.getUser_id(), accountUserBase.getUser_is_admin()) == null) {
|
||||
return CommonResult.failed(_("账号绑定失败!"));
|
||||
}
|
||||
}
|
||||
@ -3162,7 +3163,7 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl<AccountUserBaseM
|
||||
params.put("client_id", AuthConstant.MOBILE_CLIENT_ID);
|
||||
params.put("client_secret", AuthConstant.AUTHORITY_MOBILE_SECRET);
|
||||
params.put("grant_type", "password");
|
||||
params.put("verify_pwd", "1001"); // 是否验证密码 1001-不验证;1002-验证(内部登录没有用户明文密码,只能不验证)
|
||||
params.put("verify_pwd", "1001"); // 是否验证密码 1001:不验证;1002:验证(内部登录没有用户明文密码,只能不验证)
|
||||
params.put("username", mobile);
|
||||
params.put("password", "");
|
||||
params.put("user_mobile", mobile);
|
||||
|
||||
@ -399,7 +399,7 @@ public class AccountUserBindConnectServiceImpl extends BaseServiceImpl<AccountUs
|
||||
.eq("bind_active", CommonConstant.Enable)
|
||||
.orderByAsc("bind_time");
|
||||
|
||||
AccountUserBindConnect accountUserBindConnect = getOne(queryWrapper);
|
||||
AccountUserBindConnect accountUserBindConnect = findOne(queryWrapper);
|
||||
if (accountUserBindConnect != null) {
|
||||
return accountUserBindConnect;
|
||||
}
|
||||
@ -413,7 +413,7 @@ public class AccountUserBindConnectServiceImpl extends BaseServiceImpl<AccountUs
|
||||
record.setBind_openid(wxUserInfoReq.getOpenId());
|
||||
record.setBind_unionid(wxUserInfoReq.getUnionId());
|
||||
record.setBind_gender(wxUserInfoReq.getGender());
|
||||
record.setBind_nickname(wxUserInfoReq.getNickName() + mobile);
|
||||
record.setBind_nickname(wxUserInfoReq.getNickName());
|
||||
record.setBind_icon(wxUserInfoReq.getAvatarUrl());
|
||||
record.setBind_country(wxUserInfoReq.getCountry());
|
||||
record.setBind_province(wxUserInfoReq.getProvince());
|
||||
|
||||
@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@ -67,8 +66,8 @@ public class AnalyticsUserServiceImpl implements AnalyticsUserService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (yestodayRegUser.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (todayRegUser.getNum().subtract(yestodayRegUser.getNum())).divide(yestodayRegUser.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (todayRegUser.getNum().subtract(yestodayRegUser.getNum())).divide(yestodayRegUser.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -127,8 +126,8 @@ public class AnalyticsUserServiceImpl implements AnalyticsUserService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -174,92 +174,78 @@ public class OssServiceImpl implements OssService {
|
||||
String url = null;
|
||||
Integer uploadType = configService.getConfig("upload", 1);
|
||||
|
||||
if (uploadType.equals(1)) {
|
||||
url = ConfigConstant.URL_BASE + "/admin/oss/upload/" + dir + "/" + uploadName; // 文件本地路径
|
||||
} else if (uploadType.equals(2)) {
|
||||
// oss 服务
|
||||
try {
|
||||
url = uploadObject2OSS(new File(uploadPath), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(uploadName));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("文件上传失败!", e);
|
||||
return null;
|
||||
}
|
||||
} else if (uploadType.equals(4)) {
|
||||
url = uploadObject4OSS(new File(uploadPath), TENGXUN_DEFAULT_DIR.concat("/").concat(dir).concat("/").concat(uploadName));
|
||||
}
|
||||
|
||||
String media_duration = "";
|
||||
try {
|
||||
if (uploadType.equals(1)) {
|
||||
url = ConfigConstant.URL_BASE + "/admin/oss/upload/" + dir + "/" + uploadName; // 文件本地路径
|
||||
} else if (uploadType.equals(2)) {
|
||||
// oss 服务
|
||||
media_duration = VideoUtil.getFormatDuration(uploadPath);
|
||||
} catch (IOException e) {
|
||||
throw new ApiException(String.format(I18nUtil._("解析音视频时长异常!url【%s】"), uploadPath));
|
||||
}
|
||||
|
||||
//截图
|
||||
//todo 放入upload中
|
||||
String thumb_file_url = "";
|
||||
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")) {
|
||||
try {
|
||||
url = uploadObject2OSS(new File(uploadPath), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(uploadName));
|
||||
thumb_file_url = uploadObject2OSS(new File(cover_path), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/").concat(cover_upname));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("文件上传失败!", e);
|
||||
return null;
|
||||
}
|
||||
} else if (uploadType.equals(4)) {
|
||||
url = uploadObject4OSS(new File(uploadPath), TENGXUN_DEFAULT_DIR.concat("/").concat(dir).concat("/").concat(uploadName));
|
||||
}
|
||||
|
||||
String media_duration = "";
|
||||
try {
|
||||
media_duration = VideoUtil.getFormatDuration(uploadPath);
|
||||
} catch (IOException e) {
|
||||
throw new ApiException(String.format(I18nUtil._("解析音视频时长异常!url【%s】"), uploadPath));
|
||||
}
|
||||
|
||||
//截图
|
||||
//todo 放入upload中
|
||||
String thumb_file_url = "";
|
||||
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")) {
|
||||
try {
|
||||
thumb_file_url = uploadObject2OSS(new File(cover_path), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/").concat(cover_upname));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
thumb_file_url = "";
|
||||
}
|
||||
} else {
|
||||
thumb_file_url = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 保存文件信息
|
||||
MediaDTO mediaDTO = new MediaDTO();
|
||||
String name = file.getOriginalFilename();
|
||||
long size = file.getSize();
|
||||
|
||||
mediaDTO.setMedia_name(name);
|
||||
mediaDTO.setMedia_alt(name);
|
||||
mediaDTO.setMedia_size(size);
|
||||
mediaDTO.setMedia_url(url);
|
||||
mediaDTO.setMedia_order(1);
|
||||
mediaDTO.setMedia_path("/".concat(dir).concat("/").concat(uploadName));
|
||||
mediaDTO.setMedia_domain(getOssUrlPrefix().concat(ALIYUN_OSS_DIR_PREFIX));
|
||||
mediaDTO.setMedia_time(new Date());
|
||||
mediaDTO.setMedia_desc("");
|
||||
mediaDTO.setMedia_duration(media_duration);
|
||||
|
||||
shopStoreMediaService.saveMedia(mediaDTO, user);
|
||||
Map result = new HashMap<>();
|
||||
result.put("media_duration", media_duration);
|
||||
result.put("media_url", url);
|
||||
result.put("thumb", thumb_file_url);
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
// 删除临时文件
|
||||
try {
|
||||
File tempFile = new File(uploadPath);
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
logger.info("临时文件已删除: {}", uploadPath);
|
||||
}
|
||||
|
||||
// 同时删除可能创建的封面文件
|
||||
String coverPath = uploadPath.replace("." + VideoUtil.getVideoFormat(uploadPath), ".jpg");
|
||||
File coverFile = new File(coverPath);
|
||||
if (coverFile.exists()) {
|
||||
coverFile.delete();
|
||||
logger.info("临时封面文件已删除: {}", coverPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("删除临时文件失败: {}", uploadPath, e);
|
||||
} else {
|
||||
thumb_file_url = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 保存文件信息
|
||||
MediaDTO mediaDTO = new MediaDTO();
|
||||
String name = file.getOriginalFilename();
|
||||
long size = file.getSize();
|
||||
|
||||
mediaDTO.setMedia_name(name);
|
||||
mediaDTO.setMedia_alt(name);
|
||||
mediaDTO.setMedia_size(size);
|
||||
mediaDTO.setMedia_url(url);
|
||||
mediaDTO.setMedia_order(1);
|
||||
mediaDTO.setMedia_path("/".concat(dir).concat("/").concat(fileName));
|
||||
|
||||
if (uploadType.equals(1)) {
|
||||
mediaDTO.setMedia_domain(ConfigConstant.URL_BASE);
|
||||
} else if (uploadType.equals(2)) {
|
||||
mediaDTO.setMedia_domain(getOssUrlPrefix().concat(ALIYUN_OSS_DIR_PREFIX));
|
||||
} else if (uploadType.equals(4)) {
|
||||
mediaDTO.setMedia_domain(TENGXUN_ENDPOINT.concat("/").concat(TENGXUN_DEFAULT_DIR));
|
||||
}
|
||||
mediaDTO.setMedia_time(new Date());
|
||||
mediaDTO.setMedia_desc("");
|
||||
mediaDTO.setMedia_duration(media_duration);
|
||||
|
||||
shopStoreMediaService.saveMedia(mediaDTO, user);
|
||||
Map result = new HashMap<>();
|
||||
result.put("media_duration", media_duration);
|
||||
result.put("media_url", url);
|
||||
result.put("thumb", thumb_file_url);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map upload(MultipartFile file, UserDto user) {
|
||||
|
||||
@ -88,25 +88,12 @@ public class CommonConstant {
|
||||
public static final String PUSH_MSG_CATE_MCH_ORDER_DETAIL = "mchOrderDetail";
|
||||
public static final String PUSH_MSG_CATE_MCH_ONLINE_ORDER_LIST = "mchOnLineOrderList";
|
||||
public static final String PUSH_MSG_CATE_MCH_ABNORMAL_ORDER_LIST = "mchAbnormalOrderList";
|
||||
public static final String PUSH_MSG_CATE_MCH_RETURN_ORDER_LIST = "mchReturnOrderList";
|
||||
public static final String PUSH_MSG_CATE_MCH_RETURN_ORDER_LIST = "mchRetrunOrderList";
|
||||
|
||||
public static final String CONF_KEY_SAME_CITY_ORDER_EXPIRE_SECONDS = "sameCityOrderExpireSeconds";
|
||||
|
||||
public static final String SPLIT_ = "diffCityOrderExpireSeconds";
|
||||
|
||||
// 订单分拆后 运费和商品子订单前缀
|
||||
public static final String Sep_DeliveryFee_Prefix = "DF_";
|
||||
public static final String Sep_GoodsFee_Prefix = "ORD_";
|
||||
|
||||
// 分账状态:1-已分账;2-未分账;3-分账已失败;
|
||||
public static final Integer Sta_Separate_Success = 1;
|
||||
public static final Integer Sta_Separate_Undone = 2;
|
||||
public static final Integer Sta_Separate_Fail = 3;
|
||||
|
||||
// 最低平台内部配送费 配置key
|
||||
public static final String Inner_Min_DeliveryFee_Key = "inner_min_delivery_fee";
|
||||
|
||||
|
||||
//秒杀活动订阅消息模板id
|
||||
public static final String BIND_SUB_TMPL_SKILL = "kiDj_hSF_ASwD-Dlgxnypi6IJBQZ12a-hEpd3zZ-Uxc";
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||
@ToString
|
||||
public class ConfigConstant {
|
||||
|
||||
public static final String VERSION = "1.0.2"; //网站版本
|
||||
public static final String VERSION = "1.0.1"; //网站版本
|
||||
|
||||
public static final Integer MAX_LIST_NUM = -1; //最大页码
|
||||
|
||||
|
||||
@ -31,11 +31,4 @@ public class RedisConstant {
|
||||
public static final String Product_Cate_Key = ConstantRedis.Cache_NameSpace + "product_cate_Key";
|
||||
|
||||
public static final String Store_Brand_Key = ConstantRedis.Cache_NameSpace + "store_brand_key";
|
||||
|
||||
public static final String SF_Order_Proc_Expire_Key = ConstantRedis.Cache_NameSpace + "sf_order_proc_expire_key__";
|
||||
|
||||
public static final String SF_Order_Proc_WillExpire_Key = ConstantRedis.Cache_NameSpace + "sf_order_proc_will_expire_key__";
|
||||
|
||||
public static final String Order_Pay_Retry_Count_Key = ConstantRedis.Cache_NameSpace + "order_pay_retry_count:";
|
||||
|
||||
}
|
||||
|
||||
@ -6,18 +6,11 @@ import com.suisung.mall.common.api.ResultCode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
@ -32,60 +25,22 @@ import java.util.stream.Collectors;
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
private static final String UNKNOWN_LOCATION = "未知位置";
|
||||
private static final String DB_ERROR_MSG = "数据库操作失败,请稍后重试";
|
||||
private static final String LOG_FORMAT = "业务异常 || URI={} || Method={} || Error={} || Location={}";
|
||||
|
||||
/**
|
||||
* 处理参数校验异常
|
||||
* 获取异常发生位置信息
|
||||
*
|
||||
* @param stackTrace 异常堆栈
|
||||
* @return 格式化的位置信息(类名.方法名 : 行号)
|
||||
*/
|
||||
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
|
||||
public CommonResult handleValidationException(Exception e, HttpServletRequest req) {
|
||||
String errorMessage;
|
||||
|
||||
if (e instanceof MethodArgumentNotValidException) {
|
||||
errorMessage = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
} else {
|
||||
errorMessage = ((BindException) e).getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
private String getExceptionLocation(StackTraceElement[] stackTrace) {
|
||||
if (stackTrace == null || stackTrace.length == 0) {
|
||||
return UNKNOWN_LOCATION;
|
||||
}
|
||||
|
||||
logError(req, "参数校验失败", e);
|
||||
return CommonResult.validateFailed("数据是否有误,请检查!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理约束违反异常
|
||||
*/
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
public CommonResult handleConstraintViolation(ConstraintViolationException e, HttpServletRequest req) {
|
||||
String errorMessage = e.getConstraintViolations().stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.joining("; "));
|
||||
|
||||
logError(req, "约束违反异常", e);
|
||||
return CommonResult.validateFailed("系统数据异常,请联系管理员!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理参数类型不匹配异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
public CommonResult handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException e, HttpServletRequest req) {
|
||||
String errorMessage = String.format("参数%s类型不匹配,需要%s类型,但接收到%s",
|
||||
e.getName(), e.getRequiredType().getSimpleName(), e.getValue());
|
||||
|
||||
logError(req, "参数类型不匹配", e);
|
||||
return CommonResult.validateFailed("参数类型不匹配");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数字格式异常和其他参数异常
|
||||
*/
|
||||
@ExceptionHandler({NumberFormatException.class, IllegalArgumentException.class})
|
||||
public CommonResult handleParameterException(Exception e, HttpServletRequest req) {
|
||||
logError(req, "参数异常", e);
|
||||
return CommonResult.validateFailed("数据格式输入有误,请检查!");
|
||||
StackTraceElement first = stackTrace[0];
|
||||
return String.format("%s.%s:%d", first.getClassName(), first.getMethodName(), first.getLineNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,12 +48,13 @@ public class GlobalExceptionHandler {
|
||||
*/
|
||||
@ExceptionHandler({SQLException.class, DataAccessException.class, Exception.class})
|
||||
public CommonResult handleSystemException(HttpServletRequest req, Exception e) {
|
||||
logError(req, e.getMessage(), e);
|
||||
String location = getExceptionLocation(e.getStackTrace());
|
||||
logger.error(LOG_FORMAT, req.getRequestURI(), req.getMethod(), e.getMessage(), location, e);
|
||||
|
||||
if (e instanceof SQLException || e instanceof DataAccessException) {
|
||||
return CommonResult.failed("系统数据异常,请联系管理员!");
|
||||
return CommonResult.failed(DB_ERROR_MSG);
|
||||
}
|
||||
return CommonResult.failed("系统内部异常,请联系管理员!");
|
||||
return CommonResult.failed(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,22 +62,12 @@ public class GlobalExceptionHandler {
|
||||
*/
|
||||
@ExceptionHandler(ApiException.class)
|
||||
public CommonResult handleApiException(HttpServletRequest req, ApiException e) {
|
||||
logError(req, e.getErrorCode() != null ? e.getErrorCode().getMessage() : e.getMessage(), e);
|
||||
String location = getExceptionLocation(e.getStackTrace());
|
||||
logger.error(LOG_FORMAT,
|
||||
req.getRequestURI(), req.getMethod(), e.getErrorCode(), location, e);
|
||||
|
||||
return StrUtil.isNotBlank(e.getMessage())
|
||||
? CommonResult.failed(e.getMessage())
|
||||
: CommonResult.failed(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录错误日志
|
||||
*/
|
||||
private void logError(HttpServletRequest req, String message, Exception e) {
|
||||
StackTraceElement[] stackTrace = e.getStackTrace();
|
||||
String location = (stackTrace == null || stackTrace.length == 0)
|
||||
? "未知位置"
|
||||
: String.format("%s.%s:%d", stackTrace[0].getClassName(), stackTrace[0].getMethodName(), stackTrace[0].getLineNumber());
|
||||
|
||||
logger.error("业务异常 || URI={} || Method={} || Error={} || Location={}",
|
||||
req.getRequestURI(), req.getMethod(), message, location, e);
|
||||
}
|
||||
}
|
||||
@ -185,9 +185,9 @@ public interface PayService {
|
||||
/**
|
||||
* 更改交易订单的订单状态和付款状态
|
||||
*
|
||||
* @param orderId 订单Id
|
||||
* @param orderStateId 订单状态,空值或0将不更新
|
||||
* @param tradeIsPaid 支付付款状态(ENUM):3010-未付款;3011-付款待审核;3012-部分付款;3013-已付款;空值或0将不更新
|
||||
* @param orderId
|
||||
* @param orderStateId 空值或0将不更新
|
||||
* @param tradeIsPaid 空值或0将不更新
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/admin/pay/pay-consume-trade/change/state")
|
||||
|
||||
@ -311,12 +311,6 @@ public interface ShopService {
|
||||
boolean lklPayNotifyUpdateShopOrderLkl(@RequestBody JSONObject lklPayNotifyDataJson);
|
||||
|
||||
|
||||
/**
|
||||
* 终端cos上传文件
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/mobile/shop/oss/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
CommonResult uploadFile(@RequestPart(name = "upfile") MultipartFile file);
|
||||
|
||||
|
||||
@ -49,6 +49,9 @@ public class LklOrderSeparate {
|
||||
@ApiModelProperty(value = "平台订单Id")
|
||||
private String order_id;
|
||||
|
||||
@ApiModelProperty(value = "分账总金额,单位:分")
|
||||
private String total_amt;
|
||||
|
||||
@ApiModelProperty(value = "分账计算类型:0- 按照指定金额,1- 按照指定比例。默认 0")
|
||||
private String cal_type;
|
||||
|
||||
@ -76,14 +79,8 @@ public class LklOrderSeparate {
|
||||
@ApiModelProperty(value = "最终分账明细,JSON 格式")
|
||||
private String detail_datas;
|
||||
|
||||
@ApiModelProperty(value = "分账发生总金额")
|
||||
private String total_amt;
|
||||
|
||||
@ApiModelProperty(value = "实际分账金额")
|
||||
private String actual_separate_amt;
|
||||
|
||||
@ApiModelProperty(value = "分账费用")
|
||||
private String total_fee_amt;
|
||||
@ApiModelProperty(value = "总计分账金额")
|
||||
private Integer total_separate_value;
|
||||
|
||||
@ApiModelProperty(value = "拉卡拉机构编号")
|
||||
private String lkl_org_no;
|
||||
@ -94,9 +91,6 @@ public class LklOrderSeparate {
|
||||
@ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功")
|
||||
private String final_status;
|
||||
|
||||
@ApiModelProperty(value = "异步通知数据")
|
||||
private String notify_resp;
|
||||
|
||||
@ApiModelProperty(value = "分账(失败后)的标记")
|
||||
private String remark;
|
||||
|
||||
|
||||
@ -38,18 +38,10 @@ public class ShopOrderLkl implements Serializable {
|
||||
|
||||
private String order_id;
|
||||
|
||||
private String out_separate_no;
|
||||
|
||||
private Integer total_amt;
|
||||
|
||||
private Integer split_amt;
|
||||
|
||||
private Integer split_amt_ref;
|
||||
|
||||
private Integer shopping_fee;
|
||||
|
||||
private Integer shopping_fee_inner;
|
||||
|
||||
private BigDecimal split_ratio;
|
||||
|
||||
private String payment_time;
|
||||
@ -60,44 +52,24 @@ public class ShopOrderLkl implements Serializable {
|
||||
|
||||
private String trade_status;
|
||||
|
||||
private String lkl_trade_no;
|
||||
|
||||
private String lkl_log_no;
|
||||
|
||||
private String lkl_log_date;
|
||||
|
||||
private String lkl_sub_trade_no;
|
||||
|
||||
private String lkl_sub_log_no;
|
||||
|
||||
private String lkl_receive_trade_no;
|
||||
|
||||
private String lkl_receive_log_no;
|
||||
private String lkl_trade_no;
|
||||
|
||||
private String lkl_merchant_no;
|
||||
|
||||
private String lkl_term_no;
|
||||
|
||||
private String wx_transaction_id; // 微信用户交易单号, 确认收货时使用
|
||||
|
||||
private String notify_url;
|
||||
|
||||
private String receive_notify_url;
|
||||
|
||||
private String lkl_req;
|
||||
|
||||
private String lkl_resp;
|
||||
|
||||
private String lkl_notify_resp;
|
||||
|
||||
private String lkl_receive_notify_resp;
|
||||
|
||||
private Integer receive_status;
|
||||
|
||||
private Integer separate_status;
|
||||
|
||||
private String separate_remark;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Date created_at;
|
||||
|
||||
@ -78,19 +78,13 @@ public class ShopStoreBase implements Serializable {
|
||||
@ApiModelProperty(value = "店铺状态(ENUM):0-关闭; 1-运营中, 商品是否可用,需要判断该商品店铺状态")
|
||||
private Integer store_is_open;
|
||||
|
||||
@ApiModelProperty(value = "店铃声开关:1-开启;2-关闭;")
|
||||
private Integer ringtone_is_enable;
|
||||
|
||||
@ApiModelProperty(value = "店铺营业状态:1-营业中;2-已打烊;")
|
||||
private Integer store_biz_state;
|
||||
|
||||
@ApiModelProperty(value = "上级店铺编号:创建店铺决定,所属分销商-不可更改! 佣金公平性考虑")
|
||||
private Integer shop_parent_id;
|
||||
|
||||
@ApiModelProperty(value = "店铺二级分类编号")
|
||||
private Integer store_2nd_category_id;
|
||||
|
||||
@ApiModelProperty(value = "店铺一级分类编号")
|
||||
@ApiModelProperty(value = "店铺分类编号")
|
||||
private Integer store_category_id;
|
||||
|
||||
@ApiModelProperty(value = "店铺资料信息状态(ENUM):3210-待完善资料; 3220-等待审核; 3230-资料审核没有通过; 3240-资料审核通过,待付款")
|
||||
|
||||
@ -1,756 +0,0 @@
|
||||
package com.suisung.mall.common.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* 拉卡拉订单分账信息处理类
|
||||
* 实现基于总金额和基于可分账金额的分账算法,支持平台、代理商和商家的多级分账
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LklSeparateDTO {
|
||||
|
||||
// 基础金额属性
|
||||
private Integer totalSeparateAmount; // 分账总金额(分)
|
||||
private Integer canSeparateAmount; // 可分账金额(分)
|
||||
private Integer refCanSeparateAmount; // 拉卡拉参考可分账金额(分)
|
||||
private Integer shippingFee; // 配送费(分)
|
||||
|
||||
// 分账比例属性
|
||||
private BigDecimal lklRatio; // 拉卡拉分账比例(如 0.0025=0.25%)
|
||||
private BigDecimal mchRatio; // 商户分账比例(如 0.96=96%)
|
||||
private BigDecimal platRatio; // 平台分账比例(如 0.01=1%)
|
||||
private BigDecimal agent1stRatio; // 一级代理商分账比例(如 0.01=1%)
|
||||
private BigDecimal agent2ndRatio; // 二级代理商分账比例(如 0.03=3%)
|
||||
|
||||
// 分账金额结果属性
|
||||
private Integer lklAmount; // 拉卡拉分账金额(分)
|
||||
private Integer mchAmount; // 商户分账金额(分)
|
||||
private Integer platAmount; // 平台分账金额(分)
|
||||
private Integer agent1stAmount; // 一级代理商分账金额(分)
|
||||
private Integer agent2ndAmount; // 二级代理商分账金额(分)
|
||||
|
||||
/**
|
||||
* 测试方法
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 创建分账对象
|
||||
LklSeparateDTO dto = new LklSeparateDTO();
|
||||
|
||||
// 设置测试参数 - 正常情况
|
||||
dto.setTotalSeparateAmount(1000); // 分账总额 1000分
|
||||
dto.setShippingFee(100); // 配送费 100分
|
||||
dto.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025
|
||||
dto.setMchRatio(new BigDecimal("0.94")); // 商家分账比例 0.94
|
||||
dto.setPlatRatio(new BigDecimal("0.06")); // 平台分账比例 0.01
|
||||
// dto.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 0.01
|
||||
// dto.setAgent2ndRatio(new BigDecimal("0.01")); // 二级代理商分账比例 0.01
|
||||
|
||||
// 执行基于总金额的分账算法
|
||||
System.out.println("=== 基于总金额的分账算法测试(正常情况) ===");
|
||||
SharingResult result1 = dto.sharingOnTotalAmount();
|
||||
System.out.println(result1);
|
||||
if (result1.isSuccess()) {
|
||||
printSharingDetails(dto, "基于总金额");
|
||||
}
|
||||
|
||||
// 测试基于可分账金额的分账算法(正常情况)
|
||||
System.out.println("\n=== 基于可分账金额的分账算法测试(正常情况) ===");
|
||||
LklSeparateDTO dto2 = new LklSeparateDTO();
|
||||
dto2.setTotalSeparateAmount(1); // 分账总额 1000分
|
||||
dto2.setShippingFee(0); // 配送费 100分
|
||||
// dto2.setRefCanSeparateAmount(null);
|
||||
dto2.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025
|
||||
dto2.setMchRatio(new BigDecimal("0.94")); // 商家分账比例 0.857 (会产生小数)
|
||||
dto2.setPlatRatio(new BigDecimal("0.01")); // 平台分账比例 0.01
|
||||
// 不设置一级和二级代理商分账比例,测试不参与分账的情况
|
||||
// dto2.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 0.023 (会产生小数)
|
||||
// dto2.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例 0.031 (会产生小数)
|
||||
|
||||
SharingResult result2 = dto2.sharingOnCanSeparateAmount();
|
||||
System.out.println(result2);
|
||||
if (result2.isSuccess()) {
|
||||
printSharingDetails(dto2, "基于可分账金额");
|
||||
}
|
||||
|
||||
// 测试toJSON和toString方法
|
||||
System.out.println("\n=== toJSON和toString方法测试 ===");
|
||||
System.out.println("基于可分账金额算法的JSON输出:");
|
||||
System.out.println(dto2.toJSON());
|
||||
|
||||
System.out.println("\n基于可分账金额算法的toString输出:");
|
||||
System.out.println(dto2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算百分比
|
||||
*
|
||||
* @param amount 金额
|
||||
* @param total 总金额
|
||||
* @return 百分比字符串,保留两位小数
|
||||
*/
|
||||
public static String calculatePercentage(Integer amount, Integer total) {
|
||||
if (amount == null || total == null || total == 0) {
|
||||
return "0.00";
|
||||
}
|
||||
BigDecimal percentage = new BigDecimal(amount).multiply(new BigDecimal("100"))
|
||||
.divide(new BigDecimal(total), 2, RoundingMode.HALF_UP);
|
||||
return percentage.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印分账详情
|
||||
*
|
||||
* @param dto 分账对象
|
||||
* @param type 分账类型
|
||||
*/
|
||||
private static void printSharingDetails(LklSeparateDTO dto, String type) {
|
||||
System.out.println(type + "分账详情:");
|
||||
if (dto.getTotalSeparateAmount() != null) {
|
||||
System.out.println(" 分账总金额: " + dto.getTotalSeparateAmount() + "分");
|
||||
}
|
||||
// 打印拉卡拉分账金额(即使为0也要显示)
|
||||
if (dto.getLklAmount() != null) {
|
||||
System.out.println(" 拉卡拉分账金额: " + dto.getLklAmount() + "分" +
|
||||
" (占比: " + calculatePercentage(dto.getLklAmount(), dto.getTotalSeparateAmount()) + "%)");
|
||||
}
|
||||
// 打印配送费(即使为0也要显示)
|
||||
if (dto.getShippingFee() != null) {
|
||||
System.out.println(" 配送费: " + dto.getShippingFee() + "分" +
|
||||
" (占比: " + calculatePercentage(dto.getShippingFee(), dto.getTotalSeparateAmount()) + "%)");
|
||||
}
|
||||
if (dto.getCanSeparateAmount() != null) {
|
||||
System.out.println(" 可分账金额: " + dto.getCanSeparateAmount() + "分");
|
||||
}
|
||||
if (dto.getRefCanSeparateAmount() != null) {
|
||||
System.out.println(" 参考可分账金额: " + dto.getRefCanSeparateAmount() + "分");
|
||||
}
|
||||
if (dto.getCanSeparateAmount() != null && dto.getRefCanSeparateAmount() != null) {
|
||||
System.out.println(" 参考可分账差值: " + (dto.getRefCanSeparateAmount() - dto.getCanSeparateAmount()) + "分");
|
||||
}
|
||||
if (dto.getPlatAmount() != null) {
|
||||
System.out.println(" 平台分账金额: " + dto.getPlatAmount() + "分" +
|
||||
(dto.getTotalSeparateAmount() != null ?
|
||||
" (总金额占比: " + calculatePercentage(dto.getPlatAmount(), dto.getTotalSeparateAmount()) + "%)" : "") +
|
||||
(dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ?
|
||||
" (可分账占比: " + calculatePercentage(dto.getPlatAmount(), dto.getCanSeparateAmount()) + "%)" : ""));
|
||||
}
|
||||
if (dto.getAgent1stAmount() != null) {
|
||||
System.out.println(" 一级代理商分账金额: " + dto.getAgent1stAmount() + "分" +
|
||||
(dto.getTotalSeparateAmount() != null ?
|
||||
" (总金额占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getTotalSeparateAmount()) + "%)" : "") +
|
||||
(dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ?
|
||||
" (可分账占比: " + calculatePercentage(dto.getAgent1stAmount(), dto.getCanSeparateAmount()) + "%)" : ""));
|
||||
}
|
||||
if (dto.getAgent2ndAmount() != null) {
|
||||
System.out.println(" 二级代理商分账金额: " + dto.getAgent2ndAmount() + "分" +
|
||||
(dto.getTotalSeparateAmount() != null ?
|
||||
" (总金额占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getTotalSeparateAmount()) + "%)" : "") +
|
||||
(dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ?
|
||||
" (可分账占比: " + calculatePercentage(dto.getAgent2ndAmount(), dto.getCanSeparateAmount()) + "%)" : ""));
|
||||
}
|
||||
if (dto.getMchAmount() != null) {
|
||||
System.out.println(" 商家分账金额: " + dto.getMchAmount() + "分" +
|
||||
(dto.getTotalSeparateAmount() != null ?
|
||||
" (总金额占比: " + calculatePercentage(dto.getMchAmount(), dto.getTotalSeparateAmount()) + "%)" : "") +
|
||||
(dto.getCanSeparateAmount() != null && dto.getCanSeparateAmount() > 0 ?
|
||||
" (可分账占比: " + calculatePercentage(dto.getMchAmount(), dto.getCanSeparateAmount()) + "%)" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账算法 - 基于总金额进行分账
|
||||
*
|
||||
* @return SharingResult 分账结果,包含是否成功和失败原因
|
||||
*/
|
||||
public SharingResult sharingOnTotalAmount() {
|
||||
// 执行基于总金额的分账计算
|
||||
SharingCalculationResult result = calculateBasedOnTotalAmount();
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// 更新实例变量
|
||||
this.lklAmount = result.getLklAmount();
|
||||
this.canSeparateAmount = result.getCanSeparateAmount();
|
||||
this.refCanSeparateAmount = result.getRefCanSeparateAmount();
|
||||
this.shippingFee = result.getShippingFee();
|
||||
this.platAmount = result.getPlatAmount();
|
||||
this.agent1stAmount = result.getAgent1stAmount();
|
||||
this.agent2ndAmount = result.getAgent2ndAmount();
|
||||
this.mchAmount = result.getMchAmount();
|
||||
return new SharingResult(true, null);
|
||||
} else {
|
||||
return new SharingResult(false, result.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于总金额的分账计算(独立算法)
|
||||
*
|
||||
* @return SharingCalculationResult 计算结果
|
||||
*/
|
||||
private SharingCalculationResult calculateBasedOnTotalAmount() {
|
||||
// 1. 参数校验
|
||||
if (totalSeparateAmount == null || totalSeparateAmount <= 0) {
|
||||
return new SharingCalculationResult(false, "分账总金额不能为空或小于等于0");
|
||||
}
|
||||
|
||||
// 2. 计算拉卡拉分账金额
|
||||
int lklAmount = calculateAmountWithRatio(lklRatio, totalSeparateAmount, RoundingMode.HALF_UP);
|
||||
|
||||
// 3. 处理配送费(可以为空或0,表示免配送费)
|
||||
int effectiveShippingFee = (shippingFee != null && shippingFee > 0) ? shippingFee : 0;
|
||||
|
||||
// 4. 检查配送费是否合法(不能大于等于可分账金额)
|
||||
if (effectiveShippingFee >= totalSeparateAmount - lklAmount) {
|
||||
return new SharingCalculationResult(false, "配送费不能大于等于可分账金额");
|
||||
}
|
||||
|
||||
// 5. 计算可分账金额(总金额 - 拉卡拉分账金额 - 配送费)
|
||||
int availableAmount = totalSeparateAmount - lklAmount - effectiveShippingFee;
|
||||
if (availableAmount < 0) {
|
||||
return new SharingCalculationResult(false, "可分账金额不能为负数");
|
||||
}
|
||||
|
||||
int canSeparateAmount = availableAmount;
|
||||
// 保持canSeparateAmount和refCanSeparateAmount的独立性,不进行相互赋值
|
||||
|
||||
// 记录refCanSeparateAmount相关信息
|
||||
System.out.println("基于总金额算法 - 可分账金额计算完成: canSeparateAmount=" + canSeparateAmount +
|
||||
", refCanSeparateAmount=" + this.refCanSeparateAmount);
|
||||
|
||||
// 5.1 检查refCanSeparateAmount是否为有效值,如果是有效值且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账金额
|
||||
int separateAmountForCalculation = canSeparateAmount; // 默认使用计算出的可分账金额
|
||||
if (this.refCanSeparateAmount != null && this.refCanSeparateAmount > 0 && this.refCanSeparateAmount < totalSeparateAmount) {
|
||||
// refCanSeparateAmount是非空非零且比totalSeparateAmount小的有效值
|
||||
if (!this.refCanSeparateAmount.equals(canSeparateAmount)) {
|
||||
// 有效值如果和计算出来的canSeparateAmount的值不一致
|
||||
separateAmountForCalculation = this.refCanSeparateAmount; // 使用refCanSeparateAmount作为分账算法中的可分金额
|
||||
System.out.println("基于总金额算法 - 使用refCanSeparateAmount作为分账金额: refCanSeparateAmount=" +
|
||||
this.refCanSeparateAmount + ", canSeparateAmount=" + canSeparateAmount +
|
||||
", 差值=" + (this.refCanSeparateAmount - canSeparateAmount));
|
||||
} else {
|
||||
System.out.println("基于总金额算法 - refCanSeparateAmount与canSeparateAmount相等,无需调整");
|
||||
}
|
||||
} else {
|
||||
System.out.println("基于总金额算法 - refCanSeparateAmount无效,使用计算出的canSeparateAmount");
|
||||
}
|
||||
|
||||
// 6. 初始化各分账金额
|
||||
int platAmount = 0;
|
||||
int agent1stAmount = 0;
|
||||
int agent2ndAmount = 0;
|
||||
int mchAmount = 0;
|
||||
|
||||
// 7. 根据参与方动态调整分账比例(基于总金额的独立逻辑)
|
||||
BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveMchRatio = mchRatio != null ? mchRatio : BigDecimal.ZERO;
|
||||
|
||||
// 判断代理商是否参与分账(在调整比例前进行判断)
|
||||
boolean hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
boolean hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
|
||||
// 根据商家分账比例动态调整其他方比例(独立于基于可分账金额的算法)
|
||||
if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal remainingRatio = BigDecimal.ONE.subtract(effectiveMchRatio);
|
||||
BigDecimal onePercent = new BigDecimal("0.01");
|
||||
|
||||
if (hasAgent1st && hasAgent2nd) {
|
||||
// 平台、一级代理商、二级代理商都参与
|
||||
// 平台固定1%,一级代理商固定1%,二级代理商为剩余比例
|
||||
effectivePlatRatio = onePercent;
|
||||
effectiveAgent1stRatio = onePercent;
|
||||
effectiveAgent2ndRatio = remainingRatio.subtract(onePercent).subtract(onePercent);
|
||||
} else if (hasAgent1st || hasAgent2nd) {
|
||||
// 只有平台和一个代理商参与
|
||||
effectivePlatRatio = onePercent;
|
||||
// 代理商为剩余比例
|
||||
if (hasAgent1st) {
|
||||
effectiveAgent1stRatio = remainingRatio.subtract(onePercent);
|
||||
} else {
|
||||
effectiveAgent2ndRatio = remainingRatio.subtract(onePercent);
|
||||
}
|
||||
} else {
|
||||
// 只有平台参与
|
||||
effectivePlatRatio = remainingRatio;
|
||||
}
|
||||
|
||||
// 重新判断代理商是否参与分账(基于调整后的比例)
|
||||
hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
// 如果商家比例不存在或为0,使用各自设置的固定比例,代理商参与状态已在前面确定
|
||||
|
||||
// 8. 按优先级顺序计算各分账方金额
|
||||
// 平台分账(优先级1)- 基于总金额计算
|
||||
if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
platAmount = calculateAmountWithRatio(effectivePlatRatio, totalSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保平台分账金额不超过可分账金额
|
||||
if (platAmount > separateAmountForCalculation) {
|
||||
platAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= platAmount;
|
||||
}
|
||||
|
||||
// 一级代理商分账(优先级2)- 基于总金额计算
|
||||
if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
agent1stAmount = calculateAmountWithRatio(effectiveAgent1stRatio, totalSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保不超过剩余金额
|
||||
if (agent1stAmount > separateAmountForCalculation) {
|
||||
agent1stAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= agent1stAmount;
|
||||
}
|
||||
|
||||
// 二级代理商分账(优先级3)- 基于总金额计算
|
||||
if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
agent2ndAmount = calculateAmountWithRatio(effectiveAgent2ndRatio, totalSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保不超过剩余金额
|
||||
if (agent2ndAmount > separateAmountForCalculation) {
|
||||
agent2ndAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= agent2ndAmount;
|
||||
}
|
||||
|
||||
// 9. 商家分账(优先级4,获得剩余所有金额)
|
||||
mchAmount = separateAmountForCalculation;
|
||||
|
||||
// 10. 检查商家分账金额是否合法
|
||||
if (mchAmount < 0) {
|
||||
return new SharingCalculationResult(false, "商家分账金额不能为负数");
|
||||
}
|
||||
|
||||
// 创建并返回计算结果
|
||||
SharingCalculationResult calculationResult = new SharingCalculationResult(true, null);
|
||||
calculationResult.setLklAmount(lklAmount);
|
||||
calculationResult.setCanSeparateAmount(canSeparateAmount);
|
||||
calculationResult.setRefCanSeparateAmount(this.refCanSeparateAmount);
|
||||
calculationResult.setShippingFee(effectiveShippingFee);
|
||||
calculationResult.setPlatAmount(platAmount);
|
||||
calculationResult.setAgent1stAmount(agent1stAmount);
|
||||
calculationResult.setAgent2ndAmount(agent2ndAmount);
|
||||
calculationResult.setMchAmount(mchAmount);
|
||||
|
||||
return calculationResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账算法 - 基于可分账金额进行分账
|
||||
*
|
||||
* @return SharingResult 分账结果,包含是否成功和失败原因
|
||||
*/
|
||||
public SharingResult sharingOnCanSeparateAmount() {
|
||||
// 执行基于可分账金额的分账计算
|
||||
SharingCalculationResult result = calculateBasedOnCanSeparateAmount();
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// 更新实例变量
|
||||
this.lklAmount = result.getLklAmount();
|
||||
this.canSeparateAmount = result.getCanSeparateAmount();
|
||||
this.refCanSeparateAmount = result.getRefCanSeparateAmount();
|
||||
this.shippingFee = result.getShippingFee();
|
||||
this.platAmount = result.getPlatAmount();
|
||||
this.agent1stAmount = result.getAgent1stAmount();
|
||||
this.agent2ndAmount = result.getAgent2ndAmount();
|
||||
this.mchAmount = result.getMchAmount();
|
||||
return new SharingResult(true, null);
|
||||
} else {
|
||||
return new SharingResult(false, result.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于可分账金额的分账计算(独立算法)
|
||||
*
|
||||
* @return SharingCalculationResult 计算结果
|
||||
*/
|
||||
private SharingCalculationResult calculateBasedOnCanSeparateAmount() {
|
||||
// 1. 参数校验
|
||||
if (totalSeparateAmount == null || totalSeparateAmount <= 0) {
|
||||
return new SharingCalculationResult(false, "分账总金额不能为空或小于等于0");
|
||||
}
|
||||
|
||||
// 2. 先扣除配送费(可以为空或0,表示免配送费)
|
||||
int effectiveShippingFee = (shippingFee != null && shippingFee > 0) ? shippingFee : 0;
|
||||
if (effectiveShippingFee >= totalSeparateAmount) {
|
||||
return new SharingCalculationResult(false, "配送费不能大于等于分账总金额");
|
||||
}
|
||||
|
||||
// 3. 计算扣除配送费后的金额
|
||||
int amountAfterShipping = totalSeparateAmount - effectiveShippingFee;
|
||||
|
||||
// 4. 计算拉卡拉分账金额(手续费)= 分账总金额 * 拉卡拉分账比例
|
||||
int lklAmount = calculateAmountWithRatio(lklRatio, totalSeparateAmount, RoundingMode.HALF_UP);
|
||||
|
||||
// 5. 检查拉卡拉分账金额是否合法
|
||||
if (lklAmount >= amountAfterShipping) {
|
||||
return new SharingCalculationResult(false, "拉卡拉分账金额不能大于等于扣除配送费后的金额");
|
||||
}
|
||||
|
||||
// 6. 计算可分账金额 = 分账总金额 - 配送费 - 拉卡拉分账金额
|
||||
int availableAmount = amountAfterShipping - lklAmount;
|
||||
if (availableAmount < 0) {
|
||||
return new SharingCalculationResult(false, "可分账金额不能为负数");
|
||||
}
|
||||
|
||||
int canSeparateAmount = availableAmount;
|
||||
// 记录refCanSeparateAmount相关信息
|
||||
System.out.println("基于可分账金额算法 - 可分账金额计算完成: canSeparateAmount=" + canSeparateAmount +
|
||||
", refCanSeparateAmount=" + this.refCanSeparateAmount);
|
||||
|
||||
// 6.1 检查refCanSeparateAmount是否为有效值,如果是有效值且与计算出的canSeparateAmount不一致,则使用refCanSeparateAmount作为分账金额
|
||||
int separateAmountForCalculation = canSeparateAmount; // 默认使用计算出的可分账金额
|
||||
if (this.refCanSeparateAmount != null && this.refCanSeparateAmount > 0 && this.refCanSeparateAmount < totalSeparateAmount) {
|
||||
// refCanSeparateAmount是非空非零且比totalSeparateAmount小的有效值
|
||||
if (!this.refCanSeparateAmount.equals(canSeparateAmount)) {
|
||||
// 有效值如果和计算出来的canSeparateAmount的值不一致
|
||||
separateAmountForCalculation = this.refCanSeparateAmount; // 使用refCanSeparateAmount作为分账算法中的可分金额
|
||||
System.out.println("基于可分账金额算法 - 使用refCanSeparateAmount作为分账金额: refCanSeparateAmount=" +
|
||||
this.refCanSeparateAmount + ", canSeparateAmount=" + canSeparateAmount +
|
||||
", 差值=" + (this.refCanSeparateAmount - canSeparateAmount));
|
||||
} else {
|
||||
System.out.println("基于可分账金额算法 - refCanSeparateAmount与canSeparateAmount相等,无需调整");
|
||||
}
|
||||
} else {
|
||||
System.out.println("基于可分账金额算法 - refCanSeparateAmount无效,使用计算出的canSeparateAmount");
|
||||
}
|
||||
|
||||
// 7. 初始化各分账金额
|
||||
int platAmount = 0;
|
||||
int agent1stAmount = 0;
|
||||
int agent2ndAmount = 0;
|
||||
int mchAmount = 0;
|
||||
|
||||
// 8. 根据参与方动态调整分账比例(基于可分账金额的独立逻辑)
|
||||
BigDecimal effectivePlatRatio = platRatio != null ? platRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveAgent1stRatio = agent1stRatio != null ? agent1stRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveAgent2ndRatio = agent2ndRatio != null ? agent2ndRatio : BigDecimal.ZERO;
|
||||
BigDecimal effectiveMchRatio = mchRatio != null ? mchRatio : BigDecimal.ZERO;
|
||||
|
||||
// 判断代理商是否参与分账(在调整比例前进行判断)
|
||||
boolean hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
boolean hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
|
||||
// 根据商家分账比例动态调整其他方比例(独立于基于总金额的算法)
|
||||
if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal remainingRatio = BigDecimal.ONE.subtract(effectiveMchRatio);
|
||||
BigDecimal onePercent = new BigDecimal("0.01");
|
||||
|
||||
if (hasAgent1st && hasAgent2nd) {
|
||||
// 平台、一级代理商、二级代理商都参与
|
||||
// 平台固定1%,一级代理商固定1%,二级代理商为剩余比例
|
||||
effectivePlatRatio = onePercent;
|
||||
effectiveAgent1stRatio = onePercent;
|
||||
effectiveAgent2ndRatio = remainingRatio.subtract(onePercent).subtract(onePercent);
|
||||
} else if (hasAgent1st || hasAgent2nd) {
|
||||
// 只有平台和一个代理商参与
|
||||
effectivePlatRatio = onePercent;
|
||||
// 代理商为剩余比例
|
||||
if (hasAgent1st) {
|
||||
effectiveAgent1stRatio = remainingRatio.subtract(onePercent);
|
||||
} else {
|
||||
effectiveAgent2ndRatio = remainingRatio.subtract(onePercent);
|
||||
}
|
||||
} else {
|
||||
// 只有平台参与
|
||||
effectivePlatRatio = remainingRatio;
|
||||
}
|
||||
|
||||
// 重新判断代理商是否参与分账(基于调整后的比例)
|
||||
hasAgent1st = effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
hasAgent2nd = effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
// 如果商家比例不存在或为0,使用各自设置的固定比例,代理商参与状态已在前面确定
|
||||
|
||||
// 9. 按新的优先级顺序计算各分账方金额(基于可分账金额计算)
|
||||
// 商家分账(优先级1)- 基于可分账金额计算,采用向上进位方式
|
||||
if (effectiveMchRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
mchAmount = calculateAmountWithRatio(effectiveMchRatio, canSeparateAmount, RoundingMode.UP);
|
||||
// 确保商家分账金额不超过剩余金额
|
||||
if (mchAmount > separateAmountForCalculation) {
|
||||
mchAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= mchAmount;
|
||||
}
|
||||
|
||||
// 平台分账(优先级2)- 基于可分账金额计算,采用四舍五入方式
|
||||
if (effectivePlatRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
platAmount = calculateAmountWithRatio(effectivePlatRatio, canSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保平台分账金额不超过剩余金额
|
||||
if (platAmount > separateAmountForCalculation) {
|
||||
platAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= platAmount;
|
||||
}
|
||||
|
||||
// 一级代理商分账(优先级3)- 基于可分账金额计算,采用四舍五入方式
|
||||
if (hasAgent1st && effectiveAgent1stRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
agent1stAmount = calculateAmountWithRatio(effectiveAgent1stRatio, canSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保不超过剩余金额
|
||||
if (agent1stAmount > separateAmountForCalculation) {
|
||||
agent1stAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= agent1stAmount;
|
||||
}
|
||||
|
||||
// 二级代理商分账(优先级4)- 基于可分账金额计算,采用四舍五入方式
|
||||
if (hasAgent2nd && effectiveAgent2ndRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
agent2ndAmount = calculateAmountWithRatio(effectiveAgent2ndRatio, canSeparateAmount, RoundingMode.HALF_UP);
|
||||
// 确保不超过剩余金额
|
||||
if (agent2ndAmount > separateAmountForCalculation) {
|
||||
agent2ndAmount = separateAmountForCalculation;
|
||||
}
|
||||
separateAmountForCalculation -= agent2ndAmount;
|
||||
}
|
||||
|
||||
// 10. 如果还有剩余金额,将其分配给商家
|
||||
if (separateAmountForCalculation > 0) {
|
||||
mchAmount += separateAmountForCalculation;
|
||||
}
|
||||
|
||||
// 11. 检查商家分账金额是否合法
|
||||
if (mchAmount < 0) {
|
||||
return new SharingCalculationResult(false, "商家分账金额不能为负数");
|
||||
}
|
||||
|
||||
// 创建并返回计算结果
|
||||
SharingCalculationResult calculationResult = new SharingCalculationResult(true, null);
|
||||
calculationResult.setLklAmount(lklAmount);
|
||||
calculationResult.setCanSeparateAmount(canSeparateAmount);
|
||||
calculationResult.setRefCanSeparateAmount(this.refCanSeparateAmount);
|
||||
calculationResult.setShippingFee(effectiveShippingFee);
|
||||
calculationResult.setPlatAmount(platAmount);
|
||||
calculationResult.setAgent1stAmount(agent1stAmount);
|
||||
calculationResult.setAgent2ndAmount(agent2ndAmount);
|
||||
calculationResult.setMchAmount(mchAmount);
|
||||
|
||||
return calculationResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将分账信息转换为格式化的JSON字符串
|
||||
*
|
||||
* @return JSON格式的字符串
|
||||
*/
|
||||
public String toJSON() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
|
||||
// 基础金额信息
|
||||
sb.append("基础金额信息:{");
|
||||
sb.append("分账总金额:").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append("分,");
|
||||
sb.append("配送费:").append(shippingFee != null ? shippingFee : 0);
|
||||
sb.append("},");
|
||||
|
||||
// 分账比例信息
|
||||
sb.append("分账比例信息:{");
|
||||
sb.append("拉卡拉分账比例:").append(lklRatio != null ? lklRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("商家分账比例:").append(mchRatio != null ? mchRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("平台分账比例:").append(platRatio != null ? platRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("一级代理商分账比例:").append(agent1stRatio != null ? agent1stRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("二级代理商分账比例:").append(agent2ndRatio != null ? agent2ndRatio.stripTrailingZeros().toPlainString() : "0");
|
||||
sb.append("},");
|
||||
|
||||
// 分账金额结果
|
||||
sb.append("分账金额结果:{");
|
||||
sb.append("拉卡拉分账金额:").append(lklAmount != null ? lklAmount : 0).append("分,");
|
||||
sb.append("可分账金额:").append(canSeparateAmount != null ? canSeparateAmount : 0).append("分,");
|
||||
sb.append("参考可分账金额:").append(refCanSeparateAmount != null ? refCanSeparateAmount : 0).append("分,");
|
||||
if (canSeparateAmount != null && refCanSeparateAmount != null) {
|
||||
sb.append("参考可分账差值:").append(refCanSeparateAmount - canSeparateAmount).append("分,");
|
||||
}
|
||||
sb.append("配送费:").append(shippingFee != null ? shippingFee : 0).append("分,");
|
||||
sb.append("平台分账金额:").append(platAmount != null ? platAmount : 0).append("分,");
|
||||
sb.append("一级代理商分账金额:").append(agent1stAmount != null ? agent1stAmount : 0).append("分,");
|
||||
sb.append("二级代理商分账金额:").append(agent2ndAmount != null ? agent2ndAmount : 0).append("分,");
|
||||
sb.append("商家分账金额:").append(mchAmount != null ? mchAmount : 0).append("分");
|
||||
sb.append("}");
|
||||
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据比例计算金额
|
||||
*
|
||||
* @param ratio 比例
|
||||
* @param baseAmount 基础金额
|
||||
* @param roundingMode 舍入模式
|
||||
* @return 计算后的金额
|
||||
*/
|
||||
private int calculateAmountWithRatio(BigDecimal ratio, int baseAmount, RoundingMode roundingMode) {
|
||||
if (ratio == null || ratio.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return ratio.multiply(new BigDecimal(baseAmount))
|
||||
.setScale(0, roundingMode).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("LklSeparateDTO{");
|
||||
|
||||
// 基础金额信息
|
||||
sb.append("基础金额信息:{");
|
||||
sb.append("分账总金额:").append(totalSeparateAmount != null ? totalSeparateAmount : 0).append("分,");
|
||||
sb.append("配送费:").append(shippingFee != null ? shippingFee : 0);
|
||||
sb.append("},");
|
||||
|
||||
// 分账比例信息
|
||||
sb.append("分账比例信息:{");
|
||||
sb.append("拉卡拉分账比例:").append(lklRatio != null ? lklRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("商家分账比例:").append(mchRatio != null ? mchRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("平台分账比例:").append(platRatio != null ? platRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("一级代理商分账比例:").append(agent1stRatio != null ? agent1stRatio.stripTrailingZeros().toPlainString() : "0").append(",");
|
||||
sb.append("二级代理商分账比例:").append(agent2ndRatio != null ? agent2ndRatio.stripTrailingZeros().toPlainString() : "0");
|
||||
sb.append("},");
|
||||
|
||||
// 分账金额结果
|
||||
sb.append("分账金额结果:{");
|
||||
sb.append("拉卡拉分账金额:").append(lklAmount != null ? lklAmount : 0).append("分,");
|
||||
sb.append("可分账金额:").append(canSeparateAmount != null ? canSeparateAmount : 0).append("分,");
|
||||
sb.append("参考可分账金额:").append(refCanSeparateAmount != null ? refCanSeparateAmount : 0).append("分,");
|
||||
if (canSeparateAmount != null && refCanSeparateAmount != null) {
|
||||
sb.append("参考可分账差值:").append(refCanSeparateAmount - canSeparateAmount).append("分,");
|
||||
}
|
||||
sb.append("配送费:").append(shippingFee != null ? shippingFee : 0).append("分,");
|
||||
sb.append("平台分账金额:").append(platAmount != null ? platAmount : 0).append("分,");
|
||||
sb.append("一级代理商分账金额:").append(agent1stAmount != null ? agent1stAmount : 0).append("分,");
|
||||
sb.append("二级代理商分账金额:").append(agent2ndAmount != null ? agent2ndAmount : 0).append("分,");
|
||||
sb.append("商家分账金额:").append(mchAmount != null ? mchAmount : 0).append("分");
|
||||
sb.append("}");
|
||||
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账结果类,包含分账是否成功以及失败原因
|
||||
*/
|
||||
public static class SharingResult {
|
||||
private boolean success;
|
||||
private String errorMessage;
|
||||
|
||||
public SharingResult() {
|
||||
}
|
||||
|
||||
public SharingResult(boolean success, String errorMessage) {
|
||||
this.success = success;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return success ? "分账成功" : "分账失败: " + errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分账计算结果类,包含分账计算的详细结果
|
||||
*/
|
||||
public static class SharingCalculationResult extends SharingResult {
|
||||
// 分账金额结果属性
|
||||
private Integer lklAmount; // 拉卡拉分账金额(分)
|
||||
private Integer canSeparateAmount; // 可分账金额(分)
|
||||
private Integer refCanSeparateAmount; // 拉卡拉参考可分账金额(分)
|
||||
private Integer shippingFee; // 配送费(分)
|
||||
private Integer platAmount; // 平台分账金额(分)
|
||||
private Integer agent1stAmount; // 一级代理商分账金额(分)
|
||||
private Integer agent2ndAmount; // 二级代理商分账金额(分)
|
||||
private Integer mchAmount; // 商户分账金额(分)
|
||||
|
||||
public SharingCalculationResult() {
|
||||
}
|
||||
|
||||
public SharingCalculationResult(boolean success, String errorMessage) {
|
||||
super(success, errorMessage);
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getLklAmount() {
|
||||
return lklAmount;
|
||||
}
|
||||
|
||||
public void setLklAmount(Integer lklAmount) {
|
||||
this.lklAmount = lklAmount;
|
||||
}
|
||||
|
||||
public Integer getCanSeparateAmount() {
|
||||
return canSeparateAmount;
|
||||
}
|
||||
|
||||
public void setCanSeparateAmount(Integer canSeparateAmount) {
|
||||
this.canSeparateAmount = canSeparateAmount;
|
||||
}
|
||||
|
||||
public Integer getRefCanSeparateAmount() {
|
||||
return refCanSeparateAmount;
|
||||
}
|
||||
|
||||
public void setRefCanSeparateAmount(Integer refCanSeparateAmount) {
|
||||
this.refCanSeparateAmount = refCanSeparateAmount;
|
||||
}
|
||||
|
||||
public Integer getShippingFee() {
|
||||
return shippingFee;
|
||||
}
|
||||
|
||||
public void setShippingFee(Integer shippingFee) {
|
||||
this.shippingFee = shippingFee;
|
||||
}
|
||||
|
||||
public Integer getPlatAmount() {
|
||||
return platAmount;
|
||||
}
|
||||
|
||||
public void setPlatAmount(Integer platAmount) {
|
||||
this.platAmount = platAmount;
|
||||
}
|
||||
|
||||
public Integer getAgent1stAmount() {
|
||||
return agent1stAmount;
|
||||
}
|
||||
|
||||
public void setAgent1stAmount(Integer agent1stAmount) {
|
||||
this.agent1stAmount = agent1stAmount;
|
||||
}
|
||||
|
||||
public Integer getAgent2ndAmount() {
|
||||
return agent2ndAmount;
|
||||
}
|
||||
|
||||
public void setAgent2ndAmount(Integer agent2ndAmount) {
|
||||
this.agent2ndAmount = agent2ndAmount;
|
||||
}
|
||||
|
||||
public Integer getMchAmount() {
|
||||
return mchAmount;
|
||||
}
|
||||
|
||||
public void setMchAmount(Integer mchAmount) {
|
||||
this.mchAmount = mchAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,12 +8,7 @@
|
||||
|
||||
package com.suisung.mall.common.service.impl;
|
||||
|
||||
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.StateCode;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -145,117 +140,6 @@ public class CommonService {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getLklCombineSplitRespInfo("8226330541100GU", "[{\"sub_trade_no\":\"20250911110110000066202050017882\",\"sub_log_no\":\"66202050017882\",\"origin_sub_trade_no\":\"20250911110113130266250044162421\",\"origin_sub_log_no\":\"66250044162421\",\"merchant_no\":\"822584059990FYP\",\"term_no\":\"N5811590\",\"amount\":\"1\"},{\"sub_trade_no\":\"20250911110110000066202050152097\",\"sub_log_no\":\"66202050152097\",\"origin_sub_trade_no\":\"20250911110113130266250044162422\",\"origin_sub_log_no\":\"66250044162422\",\"merchant_no\":\"8226330541100GU\",\"term_no\":\"N5817779\",\"amount\":\"1\"}]", false));
|
||||
System.out.println(isValidInput("", "+8618924071446"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从拉卡拉分账响应信息中提取合单运费或商品订单信息
|
||||
* <p>该方法用于处理合单支付场景,从拉卡拉返回的分账信息中筛选出运费子单或商品子单信息</p>
|
||||
*
|
||||
* @param merchantNo 商家商户号
|
||||
* @param outSplitRspInfos 拉卡拉分账响应信息,格式为JSON数组字符串:
|
||||
* [
|
||||
* {
|
||||
* "sub_trade_no":"20250830110113130266250034401288", // 子交易流水号
|
||||
* "merchant_no":"822584059990FYP", // 商户号
|
||||
* "amount":"1", // 分账金额
|
||||
* "settle_type":"0", // 结算类型
|
||||
* "sub_log_no":"66250034401288", // 子流水号
|
||||
* "out_sub_trade_no":"DF-DD-20250830-21", // 外部子交易订单号(DF开头为运费订单)
|
||||
* "term_no":"N5811590" // 终端设备号
|
||||
* },
|
||||
* {
|
||||
* "sub_trade_no":"20250830110113130266250034401289", // 子交易流水号
|
||||
* "merchant_no":"8226330541100GU", // 商户号
|
||||
* "amount":"1", // 分账金额
|
||||
* "settle_type":"0", // 结算类型
|
||||
* "sub_log_no":"66250034401289", // 子流水号
|
||||
* "out_sub_trade_no":"ORD-DD-20250830-21", // 外部子交易订单号(ORD开头为商品订单)
|
||||
* "term_no":"N5817779" // 终端设备号
|
||||
* }
|
||||
* ]
|
||||
* @param isDeliveryFee true: 提取运费子单信息, false: 提取商品子单信息
|
||||
* @return JSONObject 返回匹配的子单信息,格式如下:
|
||||
* {
|
||||
* "sub_trade_no":"20250830110113130266250034401288",
|
||||
* "merchant_no":"822584059990FYP",
|
||||
* "amount":"1",
|
||||
* "settle_type":"0",
|
||||
* "sub_log_no":"66250034401288",
|
||||
* "out_sub_trade_no":"DF-DD-20250830-21",
|
||||
* "term_no":"N5811590"
|
||||
* }
|
||||
*/
|
||||
public static JSONObject getLklCombineSplitRespInfo(String merchantNo, String outSplitRspInfos, boolean isDeliveryFee) {
|
||||
log.debug("[拉卡拉合单数据拆分] 开始获取合单数据: merchantNo={} isDeliveryFee={} outSplitRspInfos长度={}",
|
||||
merchantNo, isDeliveryFee, outSplitRspInfos != null ? outSplitRspInfos.length() : 0);
|
||||
|
||||
// 输入参数校验:检查分账信息是否为空
|
||||
if (StrUtil.isBlank(outSplitRspInfos)) {
|
||||
log.warn("[拉卡拉合单数据拆分] 合单数据为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 解析JSON数组:将字符串转换为JSONArray对象
|
||||
JSONArray outSplitRspInfoArray;
|
||||
try {
|
||||
outSplitRspInfoArray = JSONUtil.parseArray(outSplitRspInfos);
|
||||
log.debug("[拉卡拉合单数据拆分] JSON解析完成,数组大小={}", outSplitRspInfoArray.size());
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉合单数据拆分] JSON解析失败:{}", outSplitRspInfos, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查解析后的数组是否为空
|
||||
if (outSplitRspInfoArray.isEmpty()) {
|
||||
log.warn("[拉卡拉合单数据拆分] 拆分合单数据失败:分账信息数组为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 遍历JSON数组查找匹配的子单 (合单订单通常只有两个子单:一个运费单,一个商品单)
|
||||
final String deliveryPrefix = CommonConstant.Sep_DeliveryFee_Prefix;
|
||||
final String goodsPrefix = CommonConstant.Sep_GoodsFee_Prefix;
|
||||
log.debug("[拉卡拉合单数据拆分] 开始遍历数组查找匹配子单: deliveryPrefix={} goodsPrefix={}", deliveryPrefix, goodsPrefix);
|
||||
|
||||
for (int i = 0; i < outSplitRspInfoArray.size(); i++) {
|
||||
JSONObject item = outSplitRspInfoArray.getJSONObject(i);
|
||||
|
||||
if (item == null) {
|
||||
log.debug("[拉卡拉合单数据拆分] 数组第{}项为空,跳过", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取外部子交易订单号字段和商户号
|
||||
String subMerchantNo = item.getStr("merchant_no");
|
||||
String outSubTradeNo = item.getStr("out_sub_trade_no");
|
||||
log.debug("[拉卡拉合单数据拆分] 检查第{}项: outSubTradeNo={} subMerchantNo={}", i, outSubTradeNo, subMerchantNo);
|
||||
|
||||
// 根据isDeliveryFee参数和商户号筛选对应的子单信息
|
||||
if (isDeliveryFee && StrUtil.isNotBlank(merchantNo) && !merchantNo.equals(subMerchantNo)) {
|
||||
log.debug("[拉卡拉合单数据拆分] 找到运费子单(通过商户号匹配): outSubTradeNo={} subMerchantNo={}", outSubTradeNo, subMerchantNo);
|
||||
return item;
|
||||
} else if (!isDeliveryFee && StrUtil.isNotBlank(merchantNo) && merchantNo.equals(subMerchantNo)) {
|
||||
log.debug("[拉卡拉合单数据拆分] 找到商品子单(通过商户号匹配): outSubTradeNo={} subMerchantNo={}", outSubTradeNo, subMerchantNo);
|
||||
return item;
|
||||
} else {
|
||||
// 如果商户号匹配失败,则通过订单号前缀匹配
|
||||
if (isDeliveryFee && StrUtil.isNotBlank(outSubTradeNo) && outSubTradeNo.startsWith(deliveryPrefix)) {
|
||||
log.debug("[拉卡拉合单数据拆分] 找到运费子单(通过前缀匹配): outSubTradeNo={}", outSubTradeNo);
|
||||
return item;
|
||||
} else if (!isDeliveryFee && StrUtil.isNotBlank(outSubTradeNo) && outSubTradeNo.startsWith(goodsPrefix)) {
|
||||
log.debug("[拉卡拉合单数据拆分] 找到商品子单(通过前缀匹配): outSubTradeNo={}", outSubTradeNo);
|
||||
return item;
|
||||
} else {
|
||||
log.debug("[拉卡拉合单数据拆分] 第{}项不匹配条件: isDeliveryFee={} merchantNo={} subMerchantNo={} outSubTradeNo={}",
|
||||
i, isDeliveryFee, merchantNo, subMerchantNo, outSubTradeNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 未找到匹配的子单信息
|
||||
log.warn("[拉卡拉合单数据拆分] 未找到匹配的子单信息: merchantNo={} isDeliveryFee={}", merchantNo, isDeliveryFee);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ public class UniCloudPushServiceImpl implements UniCloudPushService {
|
||||
|
||||
try {
|
||||
JSONObject json = JSONUtil.parseObj(body);
|
||||
// log.debug("[推送服务] 原始响应: {}", json.toStringPretty());
|
||||
log.info("[推送服务] 原始响应: {}", json.toStringPretty());
|
||||
|
||||
// 解析标准响应字段
|
||||
Integer errCode = json.getInt("errCode", -1);
|
||||
|
||||
@ -356,104 +356,13 @@ public class CommonUtil {
|
||||
|
||||
/**
|
||||
* 对象去重工具
|
||||
*
|
||||
* @param keyExtractor
|
||||
* @param <T>
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
|
||||
Set<Object> seen = new HashSet<>();
|
||||
return t -> seen.add(keyExtractor.apply(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照指定比例计算分账金额
|
||||
* 分配优先级: 商家 > 平台 > 代理商
|
||||
*
|
||||
* @param totalAmount 分账总金额(单位:分)
|
||||
* @param merchantRatio 商家分账比例
|
||||
* @param platformRatioInRemaining 平台在剩余比例中的分账比例
|
||||
* @param agentRatioInRemaining 代理商在剩余比例中的分账比例
|
||||
* @return 包含商家、平台、代理商分得金额的Map
|
||||
*/
|
||||
public static Map<String, Integer> calculateProfitSharing(int totalAmount,
|
||||
BigDecimal merchantRatio,
|
||||
BigDecimal platformRatioInRemaining,
|
||||
BigDecimal agentRatioInRemaining) {
|
||||
Map<String, Integer> result = new HashMap<>();
|
||||
|
||||
// 初始化各方法定金额
|
||||
int merchantAmount = 0;
|
||||
int platformAmount = 0;
|
||||
int agentAmount = 0;
|
||||
|
||||
// 1. 计算商家按比例应得的金额(优先级最高)
|
||||
if (merchantRatio != null && merchantRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal merchantAmountDecimal = merchantRatio.multiply(new BigDecimal(totalAmount));
|
||||
merchantAmount = merchantAmountDecimal.setScale(0, RoundingMode.DOWN).intValue();
|
||||
|
||||
// 确保商家至少获得1分钱(如果商家参与分账但分配为0,且总金额大于0)
|
||||
if (merchantAmount == 0 && totalAmount > 0) {
|
||||
merchantAmount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 计算剩余金额
|
||||
int remainingAmount = totalAmount - merchantAmount;
|
||||
|
||||
// 3. 只有当有剩余金额时,才计算平台和代理商的分配
|
||||
if (remainingAmount > 0) {
|
||||
// 计算剩余比例(1 - 商家比例)
|
||||
BigDecimal remainingRatio = new BigDecimal("1");
|
||||
if (merchantRatio != null && merchantRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
remainingRatio = new BigDecimal("1").subtract(merchantRatio);
|
||||
}
|
||||
|
||||
// 如果代理商不参与分账
|
||||
if (agentRatioInRemaining == null || agentRatioInRemaining.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 所有剩余金额都给平台
|
||||
platformAmount = remainingAmount;
|
||||
} else {
|
||||
// 计算平台应得金额(基于剩余金额)
|
||||
if (platformRatioInRemaining != null && platformRatioInRemaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 平台在剩余部分中的分配 = 剩余金额 * 平台在剩余中的比例
|
||||
BigDecimal platformShareOfRemaining = platformRatioInRemaining.multiply(new BigDecimal(remainingAmount));
|
||||
platformAmount = platformShareOfRemaining.setScale(0, RoundingMode.DOWN).intValue();
|
||||
}
|
||||
|
||||
// 计算代理商应得金额(基于剩余金额)
|
||||
if (agentRatioInRemaining != null && agentRatioInRemaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 代理商在剩余部分中的分配 = 剩余金额 * 代理商在剩余中的比例
|
||||
BigDecimal agentShareOfRemaining = agentRatioInRemaining.multiply(new BigDecimal(remainingAmount));
|
||||
agentAmount = agentShareOfRemaining.setScale(0, RoundingMode.DOWN).intValue();
|
||||
}
|
||||
|
||||
// 重新计算剩余金额用于最终分配
|
||||
int finalRemainingAmount = remainingAmount - platformAmount - agentAmount;
|
||||
|
||||
// 确保平台至少获得1分钱(如果平台参与分账但分配为0,且还有剩余金额)
|
||||
if (platformRatioInRemaining != null && platformRatioInRemaining.compareTo(BigDecimal.ZERO) > 0
|
||||
&& platformAmount == 0 && finalRemainingAmount > 0) {
|
||||
platformAmount = 1;
|
||||
finalRemainingAmount--;
|
||||
}
|
||||
|
||||
// 按优先级分配剩余金额: 商家 > 平台 > 代理商
|
||||
// 剩余金额给商家(因为商家优先级最高)
|
||||
merchantAmount += finalRemainingAmount;
|
||||
}
|
||||
}
|
||||
|
||||
result.put("merchantAmount", merchantAmount);
|
||||
result.put("platformAmount", platformAmount);
|
||||
result.put("agentAmount", agentAmount);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("测试1分钱分配:");
|
||||
System.out.println(calculateProfitSharing(9800, new BigDecimal("0.94"), new BigDecimal("0.2"), new BigDecimal("0")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,14 +6,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class VideoUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(VideoUtil.class);
|
||||
public static List<String> videoAllowFiles = new ArrayList<String>() {{
|
||||
add("flv");
|
||||
add("swf");
|
||||
@ -33,6 +31,7 @@ public class VideoUtil {
|
||||
add("wav");
|
||||
add("mid");
|
||||
}};
|
||||
private static Logger logger = LoggerFactory.getLogger(VideoUtil.class);
|
||||
|
||||
/**
|
||||
* 得到语音或视频文件时长,单位秒 并格式化
|
||||
@ -52,43 +51,11 @@ public class VideoUtil {
|
||||
* @return 单位为毫秒
|
||||
*/
|
||||
public static long getMp4Duration(String videoPath) throws IOException {
|
||||
try {
|
||||
IsoFile isoFile = new IsoFile(videoPath);
|
||||
long lengthInSeconds =
|
||||
isoFile.getMovieBox().getMovieHeaderBox().getDuration() /
|
||||
isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
|
||||
return lengthInSeconds;
|
||||
} catch (Exception e) {
|
||||
// 处理 MOV 文件可能存在的解析问题,尝试使用 FFmpeg 获取时长
|
||||
logger.warn("无法通过 IsoFile 解析视频文件时长: {}, 尝试使用 FFmpeg", videoPath);
|
||||
try {
|
||||
return getDurationWithFFmpeg(videoPath);
|
||||
} catch (Exception ffmpegException) {
|
||||
logger.error("FFmpeg 也无法解析视频文件时长: {}", videoPath);
|
||||
throw new IOException("无法解析视频文件: " + videoPath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 FFmpeg 获取视频时长(备用方法)
|
||||
*
|
||||
* @param videoPath
|
||||
* @return 单位为毫秒
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private static long getDurationWithFFmpeg(String videoPath) throws IOException, InterruptedException {
|
||||
String command = "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 " + videoPath;
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String result = reader.readLine();
|
||||
process.waitFor();
|
||||
if (result != null) {
|
||||
// ffprobe 返回的是秒数,需要转换为毫秒
|
||||
return (long) (Double.parseDouble(result) * 1000);
|
||||
}
|
||||
throw new IOException("无法获取视频时长");
|
||||
IsoFile isoFile = new IsoFile(videoPath);
|
||||
long lengthInSeconds =
|
||||
isoFile.getMovieBox().getMovieHeaderBox().getDuration() /
|
||||
isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
|
||||
return lengthInSeconds;
|
||||
}
|
||||
|
||||
|
||||
@ -227,7 +194,8 @@ public class VideoUtil {
|
||||
int mm = (temp % 3600) / 60;
|
||||
int ss = (temp % 3600) % 60;
|
||||
|
||||
return hh != 0 ? ((hh < 10 ? ("0" + hh) : hh) + ":") : (mm < 10 ? ("0" + mm) : mm) + ":" +
|
||||
return hh != 0 ? ((hh < 10 ? ("0" + hh) : hh) + ":") : "" +
|
||||
(mm < 10 ? ("0" + mm) : mm) + ":" +
|
||||
(ss < 10 ? ("0" + ss) : ss);
|
||||
}
|
||||
}
|
||||
@ -238,7 +206,7 @@ class InputStreamRunnable extends Thread {
|
||||
|
||||
public InputStreamRunnable(InputStream is, String _type) {
|
||||
try {
|
||||
bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), StandardCharsets.UTF_8));
|
||||
bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), "UTF-8"));
|
||||
type = _type;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@ -90,7 +90,6 @@ secure:
|
||||
- "/esProduct/**"
|
||||
- "/admin/oss/upload/**"
|
||||
- "/admin/shop/wxqrcode/common/wxurlscheme"
|
||||
- "/mobile/shop/lakala/sign/ec/**"
|
||||
- "/mobile/**/**/test/case"
|
||||
- "/**/**/testcase"
|
||||
universal:
|
||||
|
||||
@ -24,10 +24,44 @@ import java.io.IOException;
|
||||
@RestController
|
||||
@RequestMapping("/mobile/pay/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);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -39,19 +39,4 @@ public interface AccountBaseConfigService extends IBaseService<AccountBaseConfig
|
||||
|
||||
boolean getTradeModePlantform();
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
*
|
||||
* @param configKey
|
||||
* @return
|
||||
*/
|
||||
String getSystemConfig(String configKey);
|
||||
|
||||
/**
|
||||
* 获取平台内部最低配送费,单位(分)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Integer getInnerMinDeliveryFee();
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import com.suisung.mall.common.constant.RedisConstant;
|
||||
import com.suisung.mall.common.feignService.AccountService;
|
||||
import com.suisung.mall.common.modules.account.AccountBaseConfig;
|
||||
@ -227,43 +226,6 @@ public class AccountBaseConfigServiceImpl extends BaseServiceImpl<AccountBaseCon
|
||||
return getTradeMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置值
|
||||
* <p>
|
||||
* 根据配置键获取对应的配置值,如果配置值为空则返回空字符串。
|
||||
* </p>
|
||||
*
|
||||
* @param configKey 配置键
|
||||
* @return 配置值,如果找不到或为空则返回空字符串
|
||||
*/
|
||||
@Override
|
||||
public String getSystemConfig(String configKey) {
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(configKey)) {
|
||||
log.warn("[系统配置] 参数校验失败:配置键不能为空");
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
String configValue = accountService.getAccountBaseConfigValue(configKey);
|
||||
return StrUtil.blankToDefault(configValue, "0");
|
||||
} catch (Exception e) {
|
||||
log.error("[系统配置] 获取配置值异常,configKey={}", configKey, e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平台内部最低配送费,单位(分)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Integer getInnerMinDeliveryFee() {
|
||||
String v = getSystemConfig(CommonConstant.Inner_Min_DeliveryFee_Key);
|
||||
return NumberUtil.isNumber(v) ? Convert.toInt(v) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易模式 2直接交易:商家直接收款; 1担保交易:平台收款,平台和商家结算。
|
||||
*/
|
||||
|
||||
@ -83,7 +83,7 @@ public class AnalytiscTradeServiceImpl implements AnalytiscTradeService {
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (yestodayTradeAmount.getAmount().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (todayTradeAmount.getAmount().subtract(yestodayTradeAmount.getAmount())).divide(yestodayTradeAmount.getAmount(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -20,16 +20,19 @@ import com.lkl.laop.sdk.LKLSDK;
|
||||
import com.lkl.laop.sdk.exception.SDKException;
|
||||
import com.lkl.laop.sdk.request.V2MmsOpenApiUploadFileRequest;
|
||||
import com.lkl.laop.sdk.request.V3LabsRelationRefundRequest;
|
||||
import com.lkl.laop.sdk.request.V3LabsTransPreorderRequest;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.feignService.ShopService;
|
||||
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||
import com.suisung.mall.common.utils.DateTimeUtils;
|
||||
import com.suisung.mall.common.utils.I18nUtil;
|
||||
import com.suisung.mall.common.utils.RestTemplateHttpUtil;
|
||||
import com.suisung.mall.pay.service.AccountBaseConfigService;
|
||||
import com.suisung.mall.pay.service.LakalaPayService;
|
||||
import com.suisung.mall.pay.service.LklLedgerMemberService;
|
||||
import com.suisung.mall.pay.service.LklLedgerMerReceiverBindService;
|
||||
import com.suisung.mall.pay.service.LklLedgerReceiverService;
|
||||
import com.suisung.mall.pay.utils.LakalaUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -79,9 +82,14 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
@Autowired
|
||||
private ShopService shopService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private AccountBaseConfigService accountBaseConfigService;
|
||||
private LklLedgerMemberService lklLedgerMemberService;
|
||||
|
||||
@Autowired
|
||||
private LklLedgerReceiverService lklLedgerReceiverService;
|
||||
|
||||
@Autowired
|
||||
private LklLedgerMerReceiverBindService lklLedgerMerReceiverBindService;
|
||||
|
||||
/**
|
||||
* 初始化 拉卡拉SDK
|
||||
@ -112,170 +120,76 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* @param storeId 店铺号
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单金额(单位:分)
|
||||
* @param totalAmount 订单金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求IP
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return 拉卡拉预下单响应结果
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONObject lklTransPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
|
||||
// 1. 参数校验
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:商户号不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("商户号不能为空!"));
|
||||
// 1. 配置初始化
|
||||
initLKLSDK();
|
||||
|
||||
if (StrUtil.isBlank(merchantNo) || StrUtil.isBlank(termNo)) {
|
||||
throw new ApiException(I18nUtil._("缺少商户号或终端号!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:终端号不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("终端号不能为空!"));
|
||||
}
|
||||
//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);
|
||||
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单号不能为空, merchantNo={}", merchantNo);
|
||||
throw new ApiException(I18nUtil._("订单号不能为空!"));
|
||||
}
|
||||
//地址位置信息
|
||||
V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo = new V3LabsTradeLocationInfo(requestIP);
|
||||
v3LabsTransPreorderWechatReq.setLocationInfo(v3LabsTradePreorderLocationInfo);
|
||||
|
||||
if (StrUtil.isBlank(subject)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单标题不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("订单标题不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(totalAmount)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:订单金额不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("订单金额不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(notifyURL)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:回调地址不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("回调地址不能为空!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(requestIP)) {
|
||||
log.warn("[拉卡拉预下单] 参数校验失败:请求IP不能为空, orderId={}", orderId);
|
||||
throw new ApiException(I18nUtil._("请求IP不能为空!"));
|
||||
}
|
||||
|
||||
log.info("[拉卡拉预下单] 开始处理请求, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId);
|
||||
//微信主扫场景下 acc_busi_fields 域内容
|
||||
V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
|
||||
wechatBus.setSubAppid(xcxAppId); // 小程序appId
|
||||
wechatBus.setUserId(openId); // 微信 openId
|
||||
wechatBus.setDeviceInfo("WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传”WEB”
|
||||
// wechatBus.setAttach(storeId); // 附加数据,商户自定义数据,在查询交易结果时原样返回。
|
||||
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
|
||||
|
||||
try {
|
||||
// 2. 装配请求数据
|
||||
JSONObject reqData = new JSONObject();
|
||||
reqData.put("merchant_no", merchantNo);
|
||||
reqData.put("term_no", termNo);
|
||||
reqData.put("out_trade_no", orderId);
|
||||
reqData.put("subject", subject);
|
||||
// 微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户:LKLACC 网联小钱包:NUCSPAY 京东钱包:JD
|
||||
reqData.put("account_type", "WECHAT");
|
||||
// 41:NATIVE((ALIPAY,云闪付支持,京东白条分期)51:JSAPI(微信公众号支付,支付宝服务窗支付,银联JS支付,翼支付JS支付、拉卡拉钱包支付)71:微信小程序支付 61:APP支付(微信APP支付)
|
||||
reqData.put("trans_type", "51");
|
||||
reqData.put("total_amount", totalAmount); // 应支付金额,单位:分
|
||||
reqData.put("settle_type", "1"); // "0"或者空,常规结算方式,如需接拉卡拉分账通需传"1",商户未开通分账之前切记不用上送此参数。
|
||||
reqData.put("notify_url", notifyURL);
|
||||
reqData.put("remark", remark);
|
||||
reqData.put("complete_notify_url", "https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify");
|
||||
log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq));
|
||||
|
||||
// 地址位置信息
|
||||
JSONObject locationInfo = new JSONObject();
|
||||
locationInfo.put("request_ip", requestIP);
|
||||
reqData.put("location_info", locationInfo);
|
||||
|
||||
// 微信业务参数
|
||||
if (StrUtil.isNotBlank(xcxAppId) && StrUtil.isNotBlank(openId)) {
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appId
|
||||
accBusiFields.put("user_id", openId); // 微信 openId
|
||||
accBusiFields.put("device_info", "WEB"); // 终端设备号(门店号或收银设备ID),注意:PC网页或JSAPI支付请传"WEB"
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
log.debug("[拉卡拉预下单] 已添加微信业务参数, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
} else {
|
||||
log.warn("[拉卡拉预下单] 微信业务参数不完整或不需要, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
}
|
||||
|
||||
// 3. 构造请求体
|
||||
JSONObject reqBody = new JSONObject();
|
||||
reqBody.put("req_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss"));
|
||||
reqBody.put("version", "3.0");
|
||||
reqBody.put("req_data", reqData);
|
||||
|
||||
log.info("[拉卡拉预下单] 请求参数组装完成, orderId={}", orderId);
|
||||
log.debug("[拉卡拉预下单] 完整请求参数: {}", JSONUtil.toJsonStr(reqBody));
|
||||
|
||||
// 4. 发送请求
|
||||
String reqUrl = serverUrl + "/api/v3/labs/trans/preorder";
|
||||
log.info("[拉卡拉预下单] 准备发送请求, orderId={}, url={}", orderId, reqUrl);
|
||||
|
||||
String authorization = LakalaUtil.genAuthorizationByPath(priKeyPath, appId, serialNo, reqBody.toString());
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
log.error("[拉卡拉预下单] 生成签名失败, orderId={}", orderId);
|
||||
throw new ApiException("生成请求签名失败!");
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", authorization);
|
||||
header.put("Content-Type", "application/json");
|
||||
|
||||
log.debug("[拉卡拉预下单] 请求头信息生成完成, orderId={}", orderId);
|
||||
|
||||
// 使用RestTemplate发送POST请求
|
||||
ResponseEntity<JSONObject> lakalaRespEntity = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("[拉卡拉预下单] 收到响应, orderId={}, responseStatus={}", orderId, lakalaRespEntity != null ? lakalaRespEntity.getStatusCode() : "NULL");
|
||||
|
||||
// 5. 处理响应结果
|
||||
if (lakalaRespEntity == null) {
|
||||
log.warn("[拉卡拉预下单] 响应为空, orderId={}", orderId);
|
||||
//3. 发送请求
|
||||
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
|
||||
log.info("拉卡拉预下单响应数据:{}", responseStr);
|
||||
if (StrUtil.isBlank(responseStr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject respBody = lakalaRespEntity.getBody();
|
||||
log.debug("[拉卡拉预下单] 响应体内容, orderId={}, responseBody={}", orderId, respBody);
|
||||
JSONObject lakalaRespJSON = JSONUtil.parseObj(responseStr);
|
||||
|
||||
if (respBody == null) {
|
||||
log.warn("[拉卡拉预下单] 响应体为空, orderId={}", orderId);
|
||||
return null;
|
||||
}
|
||||
|
||||
String responseCode = respBody.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.warn("[拉卡拉预下单] 响应码为空, orderId={}", orderId);
|
||||
return respBody;
|
||||
}
|
||||
|
||||
// 使用安全的字符串比较方式,避免空指针异常
|
||||
if (!lklPaySuccessCode.equals(responseCode)) {
|
||||
log.warn("[拉卡拉预下单] 响应码异常, orderId={}, code={}, msg={}", orderId, responseCode, respBody.getStr("msg"));
|
||||
return respBody;
|
||||
}
|
||||
|
||||
// 平台最低配送费,单位(分)
|
||||
Integer innerMinDeliverFee = accountBaseConfigService.getInnerMinDeliveryFee();
|
||||
reqData.set("shopping_fee_inner", innerMinDeliverFee); // 平台内部最低配送费,单位(分)
|
||||
|
||||
log.info("[拉卡拉预下单] 支付成功,准备保存订单记录, orderId={}", orderId);
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
lklPayReqAndRespJson.put("req", reqData);
|
||||
lklPayReqAndRespJson.put("resp", respBody);
|
||||
|
||||
try {
|
||||
if (lakalaRespJSON != null && lakalaRespJSON.getStr("code").equals("BBS00000")) {
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
lklPayReqAndRespJson.put("req", JSONUtil.parseObj(v3LabsTransPreorderWechatReq));
|
||||
lklPayReqAndRespJson.put("resp", lakalaRespJSON);
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
log.debug("[拉卡拉预下单] 订单记录保存成功, orderId={}", orderId);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉预下单] 保存订单记录失败, orderId={}", orderId, e);
|
||||
// 不中断主流程,仅记录错误
|
||||
}
|
||||
|
||||
// 6. 返回响应结果
|
||||
log.info("[拉卡拉预下单] 处理完成, orderId={}, responseCode={}", orderId, responseCode);
|
||||
return respBody;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉预下单] 系统异常, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId, e);
|
||||
throw new ApiException("拉卡拉预下单出错:" + e.getMessage(), e);
|
||||
//4. 响应
|
||||
return lakalaRespJSON;
|
||||
} catch (SDKException e) {
|
||||
log.error("拉卡拉支付出错:", e);
|
||||
throw new ApiException(I18nUtil._("支付失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拉卡拉合单预下单(主要有运费的订单使用合单)
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=208
|
||||
@ -289,64 +203,41 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* @param storeId 店铺Id
|
||||
* @param orderId 订单号
|
||||
* @param subject 订单标题
|
||||
* @param totalAmount 订单总金额(单位:分)
|
||||
* @param agentAmount 代理商收取金额(单位:分)
|
||||
* @param totalAmount 订单总金额
|
||||
* @param agentAmount 代理商收取金额
|
||||
* @param notifyURL 回调地址
|
||||
* @param requestIP 请求IP
|
||||
* @param requestIP 请求ip
|
||||
* @param remark 备注
|
||||
* @return 拉卡拉合单预下单响应结果
|
||||
**/
|
||||
@Override
|
||||
public JSONObject lklTransMergePreOrder(String merchantNo, String termNo, String agentMerchantNo, String agentTermNo, String xcxAppId, String openId, String storeId, String orderId, String subject, String totalAmount, String agentAmount, String notifyURL, String requestIP, String remark) {
|
||||
log.info("[拉卡拉合单预下单] 开始处理请求, merchantNo={}, termNo={}, agentMerchantNo={}, agentTermNo={}, orderId={}",
|
||||
merchantNo, termNo, agentMerchantNo, agentTermNo, orderId);
|
||||
|
||||
// 1. 参数校验
|
||||
// 2. 参数校验
|
||||
if (StrUtil.isBlank(merchantNo)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:商家商户号不能为空, orderId={}", orderId);
|
||||
throw new ApiException("商家商户号不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(termNo)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:终端号不能为空, orderId={}", orderId);
|
||||
throw new ApiException("终端号不能为空!");
|
||||
}
|
||||
|
||||
// 3. 校验其他必要参数
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单号不能为空, merchantNo={}, termNo={}", merchantNo, termNo);
|
||||
throw new ApiException("订单号不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(subject)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单标题不能为空, orderId={}", orderId);
|
||||
throw new ApiException("订单标题不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(totalAmount)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:订单总金额不能为空, orderId={}", orderId);
|
||||
throw new ApiException("订单总金额不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(notifyURL)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:回调地址不能为空, orderId={}", orderId);
|
||||
throw new ApiException("回调地址不能为空!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(requestIP)) {
|
||||
log.warn("[拉卡拉合单预下单] 参数校验失败:请求IP不能为空, orderId={}", orderId);
|
||||
throw new ApiException("请求IP不能为空!");
|
||||
}
|
||||
|
||||
// 如果不符合合单交易条件,则走聚合主扫单笔交易
|
||||
if (StrUtil.isBlank(agentMerchantNo) || StrUtil.isBlank(agentTermNo) || StrUtil.isBlank(agentAmount) || "0".equals(agentAmount)) {
|
||||
log.info("[拉卡拉合单预下单] 不符合合单交易条件,转为单笔交易处理。商家商户号:{},代理商商户号:{},代理商终端号:{},代理商金额:{}",
|
||||
log.info("不符合合单交易条件,转为单笔交易处理。商家商户号:{},代理商商户号:{},代理商终端号:{},代理商金额:{}",
|
||||
merchantNo, agentMerchantNo, agentTermNo, agentAmount);
|
||||
return lklTransPreOrder(merchantNo, termNo, xcxAppId, openId, storeId, orderId, subject, totalAmount, notifyURL, requestIP, remark);
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("[拉卡拉合单预下单] 开始装配请求数据, orderId={}", orderId);
|
||||
// 2. 装配请求数据
|
||||
// 4. 装配请求数据
|
||||
JSONObject reqData = new JSONObject();
|
||||
|
||||
// 基本交易信息
|
||||
@ -359,7 +250,6 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
reqData.put("subject", subject); // 订单标题
|
||||
reqData.put("notify_url", notifyURL); // 异步通知地址
|
||||
reqData.put("remark", remark); // 备注
|
||||
reqData.put("complete_notify_url", "https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify"); // 发货类小程序确认收获后通知商户的地址
|
||||
|
||||
// 位置信息
|
||||
JSONObject locationInfo = new JSONObject();
|
||||
@ -367,42 +257,24 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
reqData.put("location_info", locationInfo);
|
||||
|
||||
// 微信业务参数
|
||||
if (StrUtil.isNotBlank(xcxAppId) && StrUtil.isNotBlank(openId)) {
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appId
|
||||
accBusiFields.put("user_id", openId); // 用户openid
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
log.debug("[拉卡拉合单预下单] 已添加微信业务参数, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
} else {
|
||||
log.warn("[拉卡拉合单预下单] 微信业务参数不完整或不需要, xcxAppId={}, openId={}", xcxAppId, openId);
|
||||
}
|
||||
JSONObject accBusiFields = new JSONObject();
|
||||
accBusiFields.put("sub_appid", xcxAppId); // 小程序appid
|
||||
accBusiFields.put("user_id", openId); // 用户openid
|
||||
reqData.put("acc_busi_fields", accBusiFields);
|
||||
|
||||
// 重要约定,订单号规则:商品订单:ORD_订单号,运费订单:DF_订单号
|
||||
// 商品子单信息
|
||||
// 重要约定,订单号规则:商品订单:ORD-订单号,运费订单:DF-订单号
|
||||
// 分单信息
|
||||
JSONObject goodsSplitInfo = new JSONObject();
|
||||
goodsSplitInfo.put("out_sub_trade_no", CommonConstant.Sep_GoodsFee_Prefix + orderId); // 商品子订单号
|
||||
goodsSplitInfo.put("out_sub_trade_no", "ORD-" + orderId); // 子订单号
|
||||
goodsSplitInfo.put("merchant_no", merchantNo); // 分账商户号
|
||||
goodsSplitInfo.put("term_no", termNo); // 分账终端号
|
||||
|
||||
// 安全转换金额,避免类型转换异常
|
||||
int totalAmountInt = 0;
|
||||
int agentAmountInt = 0;
|
||||
try {
|
||||
totalAmountInt = Convert.toInt(totalAmount);
|
||||
agentAmountInt = Convert.toInt(agentAmount);
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("[拉卡拉合单预下单] 金额转换异常, totalAmount={}, agentAmount={}, orderId={}", totalAmount, agentAmount, orderId, e);
|
||||
throw new ApiException("金额格式错误!");
|
||||
}
|
||||
|
||||
int goodsAmountInt = totalAmountInt - agentAmountInt;
|
||||
goodsSplitInfo.put("amount", Convert.toStr(goodsAmountInt)); // 分账金额
|
||||
goodsSplitInfo.put("settle_type", "1"); // "0"或者空,常规结算方式
|
||||
int totalAmountInt = Convert.toInt(totalAmount) - Convert.toInt(agentAmount);
|
||||
goodsSplitInfo.put("amount", Convert.toStr(totalAmountInt)); // 分账金额
|
||||
goodsSplitInfo.put("settle_type", "0"); // "0"或者空,常规结算方式
|
||||
goodsSplitInfo.put("sub_remark", "商品订单金额"); // 子单备注信息
|
||||
|
||||
// 运费子单信息
|
||||
JSONObject deliverySplitInfo = new JSONObject();
|
||||
deliverySplitInfo.put("out_sub_trade_no", CommonConstant.Sep_DeliveryFee_Prefix + orderId); // 运费子订单号
|
||||
deliverySplitInfo.put("out_sub_trade_no", "DF-" + orderId); // 子订单号
|
||||
deliverySplitInfo.put("merchant_no", agentMerchantNo); // 分账商户号
|
||||
deliverySplitInfo.put("term_no", agentTermNo); // 分账终端号
|
||||
deliverySplitInfo.put("amount", agentAmount); // 分账金额
|
||||
@ -414,89 +286,48 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
outSplitInfo.add(goodsSplitInfo);
|
||||
reqData.put("out_split_info", outSplitInfo);
|
||||
|
||||
log.info("[拉卡拉合单预下单] 分单信息组装完成, orderId={}, goodsAmount={}分, deliveryAmount={}分",
|
||||
orderId, goodsAmountInt, agentAmountInt);
|
||||
|
||||
// 3. 构造请求体
|
||||
// 5. 构造请求体
|
||||
JSONObject reqBody = new JSONObject();
|
||||
reqBody.put("req_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss"));
|
||||
reqBody.put("version", "3.0");
|
||||
reqBody.put("req_data", reqData);
|
||||
|
||||
log.info("[拉卡拉合单预下单] 请求参数组装完成, orderId={}", orderId);
|
||||
log.debug("[拉卡拉合单预下单] 完整请求参数: {}", JSONUtil.toJsonStr(reqBody));
|
||||
|
||||
// 4. 发送请求
|
||||
// 6. 发送请求
|
||||
String reqUrl = serverUrl + "/api/v3/labs/trans/merge/preorder";
|
||||
log.info("[拉卡拉合单预下单] 准备发送请求, orderId={}, url={}", orderId, reqUrl);
|
||||
log.info("拉卡拉合单预下单请求参数:{}", reqBody);
|
||||
|
||||
String authorization = LakalaUtil.genAuthorizationByPath(priKeyPath, appId, serialNo, reqBody.toString());
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
log.error("[拉卡拉合单预下单] 生成签名失败, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "生成请求签名失败").set("resp_data", null);
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", authorization);
|
||||
header.put("Content-Type", "application/json");
|
||||
|
||||
log.debug("[拉卡拉合单预下单] 请求头信息生成完成, orderId={}", orderId);
|
||||
// 这里的请求方法,对返回的字段进行了处理,需要注意
|
||||
ResponseEntity<JSONObject> lakalaRespJSON = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("拉卡拉合单交易响应参数:{}", lakalaRespJSON);
|
||||
|
||||
// 发送请求
|
||||
ResponseEntity<JSONObject> lakalaRespEntity = RestTemplateHttpUtil.sendPostBodyBackEntity(reqUrl, header, reqBody, JSONObject.class);
|
||||
log.info("[拉卡拉合单预下单] 收到响应, orderId={}, responseStatus={}", orderId, lakalaRespEntity != null ? lakalaRespEntity.getStatusCode() : "NULL");
|
||||
|
||||
// 5. 处理响应结果
|
||||
if (lakalaRespEntity == null) {
|
||||
log.warn("[拉卡拉合单预下单] 响应为空, orderId={}", orderId);
|
||||
// 7. 处理响应结果
|
||||
if (lakalaRespJSON == null) {
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易无响应值").set("resp_data", null);
|
||||
}
|
||||
|
||||
JSONObject respBody = lakalaRespEntity.getBody();
|
||||
log.debug("[拉卡拉合单预下单] 响应体内容, orderId={}, responseBody={}", orderId, respBody);
|
||||
JSONObject respBody = lakalaRespJSON.getBody();
|
||||
|
||||
// 6. 处理响应结果
|
||||
if (respBody == null) {
|
||||
log.warn("[拉卡拉合单预下单] 响应体为空, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易响应体为空").set("resp_data", null);
|
||||
// 7. 处理响应结果
|
||||
if (!lklPaySuccessCode.equals(respBody.getStr("code")) || respBody == null) {
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易无响应值").set("resp_data", null);
|
||||
}
|
||||
|
||||
String responseCode = respBody.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.warn("[拉卡拉合单预下单] 响应码为空, orderId={}", orderId);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易响应码为空").set("resp_data", null);
|
||||
}
|
||||
|
||||
// 使用安全的字符串比较方式,避免空指针异常
|
||||
if (!lklPaySuccessCode.equals(responseCode)) {
|
||||
log.warn("[拉卡拉合单预下单] 响应码异常, orderId={}, code={}, msg={}", orderId, responseCode, respBody.getStr("msg"));
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "拉卡拉合单交易失败:" + respBody.getStr("msg")).set("resp_data", null);
|
||||
}
|
||||
|
||||
log.info("[拉卡拉合单预下单] 支付成功,准备保存订单记录, orderId={} shopping_fee_inner={}", orderId, agentAmountInt);
|
||||
// 新增一个拉卡拉订单记录 shop_order_lkl 表
|
||||
JSONObject lklPayReqAndRespJson = new JSONObject();
|
||||
reqData.set("shopping_fee_inner", agentAmountInt); // 平台内部最低配送费,单位(分)
|
||||
|
||||
lklPayReqAndRespJson.put("req", reqData);
|
||||
lklPayReqAndRespJson.put("resp", respBody); // 返回原始响应数据
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
|
||||
try {
|
||||
// 新增 shopOrderLkl 记录
|
||||
shopService.lklPayAddShopOrderLkl(lklPayReqAndRespJson);
|
||||
log.debug("[拉卡拉合单预下单] 订单记录保存成功, orderId={}", orderId);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉合单预下单] 保存订单记录失败, orderId={}", orderId, e);
|
||||
// 不中断主流程,仅记录错误
|
||||
}
|
||||
|
||||
// 7. 返回响应结果
|
||||
log.info("[拉卡拉合单预下单] 处理完成, orderId={}, responseCode={}", orderId, responseCode);
|
||||
// 8. 返回响应结果
|
||||
return respBody;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉合单预下单] 系统异常, merchantNo={}, termNo={}, orderId={}", merchantNo, termNo, orderId, e);
|
||||
return new JSONObject().set("code", "BBS00001").set("msg", "系统异常:" + e.getMessage()).set("resp_data", null);
|
||||
log.error("拉卡拉合单交易出错,订单号:{},错误信息:", orderId, e);
|
||||
throw new ApiException("拉卡拉合单交易出错:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,7 +337,7 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
* 参考地址:https://o.lakala.com/#/home/document/detail?id=113
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param outTradeNo 外部交易订单号
|
||||
* @param outTradeNo 退货订单号,如: FX-20241214-1
|
||||
* @param originTradeNo 原拉卡拉交易流水号
|
||||
* @param refundAmount 退款金额(单位:分)
|
||||
* @param refundReason 退款原因
|
||||
@ -517,58 +348,33 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
@Override
|
||||
public Pair<Boolean, String> innerLklRefund(Integer storeId, String outTradeNo, String originTradeNo, String refundAmount, String refundReason, String lklMerchantNo, String lklTermNo) {
|
||||
try {
|
||||
log.info("[拉卡拉退款] 开始执行拉卡拉内部退款,参数: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, refundReason={}",
|
||||
log.info("开始执行拉卡拉内部退款,参数: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, refundReason={}",
|
||||
storeId, outTradeNo, originTradeNo, refundAmount, refundReason);
|
||||
|
||||
// 1. 获取请求IP
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
log.error("[拉卡拉退款] 无法获取HttpServletRequest,退款失败");
|
||||
log.error("无法获取HttpServletRequest,退款失败");
|
||||
return Pair.of(false, I18nUtil._("系统异常,无法获取请求信息!"));
|
||||
}
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
String requestIp = IpKit.getRealIp(request);
|
||||
|
||||
// 2. 校验参数
|
||||
if (ObjectUtil.isEmpty(storeId)) {
|
||||
log.warn("[拉卡拉退款] 店铺ID不能为空: storeId={}", storeId);
|
||||
return Pair.of(false, I18nUtil._("店铺ID不能为空,退款失败!"));
|
||||
if (ObjectUtil.isEmpty(storeId) || org.apache.commons.lang3.StringUtils.isAnyBlank(outTradeNo, refundAmount, originTradeNo)) {
|
||||
log.warn("退款请求参数不完整: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, requestIp={}", storeId, outTradeNo, originTradeNo, refundAmount, requestIp);
|
||||
return Pair.of(false, I18nUtil._("缺少必要参数,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(outTradeNo)) {
|
||||
log.warn("[拉卡拉退款] 外部交易订单号不能为空: outTradeNo={}", outTradeNo);
|
||||
return Pair.of(false, I18nUtil._("外部交易订单号不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(originTradeNo)) {
|
||||
log.warn("[拉卡拉退款] 原拉卡拉交易流水号不能为空: originTradeNo={}", originTradeNo);
|
||||
return Pair.of(false, I18nUtil._("原拉卡拉交易流水号不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(refundAmount)) {
|
||||
log.warn("[拉卡拉退款] 退款金额不能为空: refundAmount={}", refundAmount);
|
||||
return Pair.of(false, I18nUtil._("退款金额不能为空,退款失败!"));
|
||||
}
|
||||
|
||||
// 校验退款金额格式
|
||||
if (!refundAmount.matches("\\d+") || Integer.parseInt(refundAmount) <= 0) {
|
||||
log.warn("[拉卡拉退款] 退款金额不合法: refundAmount={}", refundAmount);
|
||||
log.warn("退款金额不合法: refundAmount={}", refundAmount);
|
||||
return Pair.of(false, I18nUtil._("退款金额不合法!"));
|
||||
}
|
||||
|
||||
// 3. 初始化拉卡拉SDK
|
||||
initLKLSDK();
|
||||
|
||||
// 4. 获取店铺的拉卡拉商户号和终端号
|
||||
ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId);
|
||||
if (shopStoreBase == null) {
|
||||
log.error("[拉卡拉退款] 无法获取店铺信息: storeId={}", storeId);
|
||||
return Pair.of(false, I18nUtil._("无法获取店铺信息,退款失败!"));
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(shopStoreBase.getLkl_merchant_no()) || StrUtil.isBlank(shopStoreBase.getLkl_term_no())) {
|
||||
log.error("[拉卡拉退款] 无法获取店铺的拉卡拉商户号或终端号: storeId={}, merchantNo={}, termNo={}",
|
||||
storeId, shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no());
|
||||
if (shopStoreBase == null || org.apache.commons.lang3.StringUtils.isAnyBlank(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no())) {
|
||||
log.error("无法获取店铺的拉卡拉商户号或终端号: storeId={}", storeId);
|
||||
return Pair.of(false, I18nUtil._("缺少商户号参数,退款失败!"));
|
||||
}
|
||||
|
||||
@ -587,44 +393,37 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
|
||||
refundRequest.setLocationInfo(new V3LabsTradeLocationInfo(requestIp, null, ""));
|
||||
|
||||
log.info("[拉卡拉退款] 请求参数: {}", JSONUtil.toJsonStr(refundRequest));
|
||||
log.info("拉卡拉退款请求参数: {}", JSONUtil.toJsonStr(refundRequest));
|
||||
|
||||
String responseString = LKLSDK.httpPost(refundRequest);
|
||||
// 6. 处理响应
|
||||
if (StrUtil.isBlank(responseString)) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款接口无响应");
|
||||
log.error("拉卡拉退款接口无响应");
|
||||
return Pair.of(false, I18nUtil._("服务端无返回值,退款失败!"));
|
||||
}
|
||||
|
||||
log.info("[拉卡拉退款] 拉卡拉退款接口响应: {}", responseString);
|
||||
log.info("拉卡拉退款接口响应: {}", responseString);
|
||||
|
||||
JSONObject lakalaResponseJson = JSONUtil.parseObj(responseString);
|
||||
if (lakalaResponseJson == null) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款接口返回值解析失败: responseString={}", responseString);
|
||||
log.error("拉卡拉退款接口返回值解析失败: responseString={}", responseString);
|
||||
return Pair.of(false, I18nUtil._("返回值解析失败,退款失败!"));
|
||||
}
|
||||
|
||||
String responseCode = lakalaResponseJson.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款响应码为空: response={}", responseString);
|
||||
return Pair.of(false, I18nUtil._("返回值格式错误,退款失败!"));
|
||||
}
|
||||
|
||||
if (!"BBS00000".equals(responseCode)) {
|
||||
if (!"BBS00000".equals(lakalaResponseJson.getStr("code"))) {
|
||||
String errorMessage = lakalaResponseJson.getStr("msg", "未知错误");
|
||||
log.error("[拉卡拉退款] 拉卡拉退款失败, 错误信息: {}, 响应码: {}", errorMessage, responseCode);
|
||||
log.error("拉卡拉退款失败, 错误信息: {}", errorMessage);
|
||||
return Pair.of(false, I18nUtil._(errorMessage));
|
||||
}
|
||||
|
||||
JSONObject responseData = lakalaResponseJson.getJSONObject("resp_data");
|
||||
log.info("[拉卡拉退款] 拉卡拉退款成功: outTradeNo={}", outTradeNo);
|
||||
log.info("拉卡拉退款成功: outTradeNo={}", outTradeNo);
|
||||
return Pair.of(true, responseData == null ? "" : responseData.toString());
|
||||
|
||||
} catch (SDKException e) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款SDK异常: ", e);
|
||||
log.error("拉卡拉退款SDK异常: ", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款SDK异常,退款失败!") + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉退款] 拉卡拉退款发生未知异常: ", e);
|
||||
log.error("拉卡拉退款发生未知异常: ", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款发生未知异常,退款失败!") + e.getMessage());
|
||||
}
|
||||
}
|
||||
@ -669,4 +468,331 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
throw new ApiException(I18nUtil._("文件上传失败!"), e);
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public CommonResult applyLedgerMer(JSONObject paramsJSON) {
|
||||
// // 1. 配置初始化
|
||||
// initLKLSDK();
|
||||
//
|
||||
// //2. 装配数据
|
||||
// V2MmsOpenApiLedgerApplyLedgerMerRequest req = new V2MmsOpenApiLedgerApplyLedgerMerRequest();
|
||||
// req.setVersion("2.0");
|
||||
// String orderNo = StringUtils.genLklOrderNo(8); // 8位随机数
|
||||
// req.setOrderNo(orderNo);
|
||||
// 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(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); //比如:G1/M00/06/64/CrFdEmBQc-aAGc_XAAAiIbS3WIE960.pdf;
|
||||
//
|
||||
// if (isProdProject()) {
|
||||
// projectDomain = projectDomain + "/api";
|
||||
// }
|
||||
// // 给拉卡拉通知的回调地址
|
||||
// String retUrl = projectDomain + "/mobile/pay/lakala/ledger/applyLedgerMerNotify";
|
||||
// req.setRetUrl(retUrl);
|
||||
//
|
||||
// paramsJSON.set("orderNo", orderNo);
|
||||
// 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 (lakalaRespJSON == null || !lakalaRespJSON.getStr("retCode").equals("000000")) {
|
||||
// throw new ApiException(I18nUtil._(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"));
|
||||
//
|
||||
// // 新增数据
|
||||
// // 将 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) {
|
||||
// // 验签
|
||||
// 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", "验签失败!");
|
||||
// }
|
||||
//
|
||||
// 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 = 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", "000000");
|
||||
// respData.put("retMsg", "操作成功!");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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<V2MmsOpenApiLedgerApplyLedgerReceiverRequest.AttachInfo> 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("000000")) {
|
||||
// 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("000000")) {
|
||||
// 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", "000000");
|
||||
// respData.put("retMsg", "操作成功!");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return respData;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -52,7 +52,6 @@ import com.suisung.mall.common.modules.pay.*;
|
||||
import com.suisung.mall.common.modules.pay.dto.ItemActivityInfoDTO;
|
||||
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||
import com.suisung.mall.common.pojo.res.ThirdApiRes;
|
||||
import com.suisung.mall.common.service.impl.CommonService;
|
||||
import com.suisung.mall.common.utils.CheckUtil;
|
||||
import com.suisung.mall.common.utils.I18nUtil;
|
||||
import com.suisung.mall.common.utils.LogUtil;
|
||||
@ -676,17 +675,9 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
cn.hutool.json.JSONObject lakalaRespJSON = new cn.hutool.json.JSONObject();
|
||||
|
||||
BigDecimal shippingFee = shopService.getOrderShippingFee(out_trade_no);
|
||||
if (shippingFee == null || shippingFee.intValue() <= 0) {
|
||||
shippingFee = BigDecimal.ZERO;
|
||||
}
|
||||
logger.debug("预支付时,查到的订单{},运费:{}", out_trade_no, shippingFee);
|
||||
|
||||
// 平台最低配送费,单位(分)
|
||||
Integer innerMinDeliverFee = accountBaseConfigService.getInnerMinDeliveryFee();
|
||||
|
||||
logger.debug("预支付时,查到的订单{},商家配送费:{}元,平台最低配送费要求:{}分", out_trade_no, shippingFee, innerMinDeliverFee);
|
||||
|
||||
// 平台最低配送费,单位(分)
|
||||
if (innerMinDeliverFee == null || innerMinDeliverFee.intValue() <= 0) {
|
||||
if (shippingFee == null || shippingFee.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 没有运费
|
||||
// 拉卡拉预支付返回参数
|
||||
lakalaRespJSON = lakalaPayService.lklTransPreOrder(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no(),
|
||||
@ -695,12 +686,11 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
requestIP, trade_remark);
|
||||
} else { // 有运费的情况
|
||||
// 拉卡拉合单预支付返回参数
|
||||
// RMK 这里只有固定一个运费代理商代收运费,以后代理商模块做好了,要动态读取店铺的运费代理商。
|
||||
// TODO RMK 这里只有固定一个运费代理商代收运费,以后代理商模块做好了,要动态读取店铺的运费代理商。
|
||||
lakalaRespJSON = lakalaPayService.lklTransMergePreOrder(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no(),
|
||||
delivery_merchant_no, delivery_term_no, // 以后根据代理商动态分配
|
||||
appId, openId, storeIdStr, out_trade_no, subject, total_amt,
|
||||
// Convert.toStr(shippingFee.multiply(BigDecimal.valueOf(100)).intValue()),
|
||||
Convert.toStr(innerMinDeliverFee),
|
||||
Convert.toStr(shippingFee.multiply(BigDecimal.valueOf(100)).intValue()),
|
||||
notifyUrl,
|
||||
requestIP, trade_remark);
|
||||
}
|
||||
@ -1354,69 +1344,51 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理拉卡拉支付异步通知
|
||||
* 该方法用于接收并处理来自拉卡拉支付平台的异步通知,包括验签、解析参数、更新订单状态等操作
|
||||
*
|
||||
* @param request HTTP请求对象,包含拉卡拉支付平台发送的异步通知数据
|
||||
* @return String 返回处理结果,用于响应拉卡拉支付平台
|
||||
*/
|
||||
@Override
|
||||
public String lklNotifyUrl(HttpServletRequest request) {
|
||||
Map<String, String> params;
|
||||
try {
|
||||
logger.info("[拉卡拉支付通知] 开始处理拉卡拉支付异步通知");
|
||||
|
||||
// 初始化拉卡拉SDK
|
||||
lakalaPayService.initLKLSDK();
|
||||
log.debug("[拉卡拉支付通知] 拉卡拉SDK初始化完成");
|
||||
|
||||
// 读取请求体并验签
|
||||
String body = LKLSDK.notificationHandle(request);
|
||||
String authorization = request.getHeader("Authorization");
|
||||
logger.debug("[拉卡拉支付通知] 接收到通知数据,body长度={},authorization长度={}",
|
||||
body != null ? body.length() : 0,
|
||||
authorization != null ? authorization.length() : 0);
|
||||
|
||||
if (StrUtil.isBlank(body)) {
|
||||
log.warn("[拉卡拉支付通知] 验签失败,请求体为空");
|
||||
return lklNotifyMsg(false, "验签失败!");
|
||||
}
|
||||
|
||||
// 敏感头信息脱敏打印
|
||||
logger.info("[拉卡拉支付通知] 拉卡拉支付异步通知回调 body:{} \n authorization: {}",
|
||||
body, authorization != null ? "***" : "null");
|
||||
logger.info("拉卡拉支付异步通知回调 body:{} \n authorization: {}", body, authorization);
|
||||
// 异步通知返回的body json数据:{"out_trade_no":"202203151637334864280014","trade_no":"2022031566210203291925","log_no":"66210203291925",
|
||||
// "acc_trade_no":"2022031522001483661454130929 ","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"1",
|
||||
// "payer_amount":"1","acc_settle_amount":"1","trade_time":"20220315163808","user_id1":"app***@163.com",
|
||||
// "user_id2":"2088432881453660","notify_url":"https://www.baidu.com","account_type":"ALIPAY","card_type":"99"}
|
||||
|
||||
// 合单返回的数据:{"out_trade_no":"DD-20250830-10","trade_no":"20250830110113130266250034160499","log_no":"66250034160499","acc_trade_no":"4200002826202508306761393882","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"2","payer_amount":"2","acc_settle_amount":"2","acc_mdiscount_amount":"0","acc_discount_amount":"0","trade_time":"20250830180435","user_id1":"oDVKR7T0qxg6O8tqIL9SgY6LXqqQ","user_id2":"oVxsc1QRAqDRv_gAmXuLZwSVSL18","notify_url":"https://mall.gpxscs.cn/mobile/pay/index/lkl_wxPay_notify_url","account_type":"WECHAT","bank_type":"OTHERS","card_type":"02","merchant_no":"8226330541100GU","remark":"","sub_mch_id":"803819329","out_split_rsp_infos":[{"sub_trade_no":"20250830110113130266250034112794","sub_log_no":"66250034112794","out_sub_trade_no":"ORD_DD-20250830-10","merchant_no":"8226330541100GU","term_no":"N5817779","amount":"1","settle_type":"0"},{"sub_trade_no":"20250830110113130266250034160498","sub_log_no":"66250034160498","out_sub_trade_no":"DF_DD-20250830-10","merchant_no":"822584059990FYP","term_no":"N5811590","amount":"1","settle_type":"0"}],"trade_req_date":"20250830","gb_amount":"","qb_amount":""}
|
||||
|
||||
// 解析JSON格式响应
|
||||
cn.hutool.json.JSONObject lklNotifyRespJSON = JSONUtil.parseObj(body);
|
||||
logger.debug("[拉卡拉支付通知] 解析JSON完成: keys={}", lklNotifyRespJSON.keySet());
|
||||
|
||||
params = Convert.toMap(String.class, String.class, lklNotifyRespJSON);
|
||||
String orderId = params.getOrDefault("out_trade_no", "");
|
||||
String tradeStatus = params.getOrDefault("trade_status", "");
|
||||
String accTradeNo = params.getOrDefault("acc_trade_no", "");
|
||||
String outSplitRspInfos = params.getOrDefault("out_split_rsp_infos", "");
|
||||
|
||||
logger.info("[拉卡拉支付通知] 核心参数 - 订单号:{} 状态:{} 是否合单:{}",
|
||||
orderId, tradeStatus, StrUtil.isNotBlank(outSplitRspInfos) ? "是" : "否");
|
||||
String accTradeNo = params.getOrDefault("acc_trade_no", ""); // 需要跟拉卡拉确认这个字段是原支付交易对应的微信订单号吗?
|
||||
String outSplitRspInfos = params.getOrDefault("out_split_rsp_infos", ""); // 拉卡拉合单订单信息
|
||||
|
||||
// 提取授权签名信息
|
||||
Map<String, String> authMap = LakalaUtil.getLakalaAuthorizationMap(authorization);
|
||||
if (authMap != null && authMap.containsKey("signature")) {
|
||||
params.put("sign", authMap.get("signature"));
|
||||
logger.debug("[拉卡拉支付通知] 签名信息提取成功");
|
||||
} else {
|
||||
logger.error("[拉卡拉支付通知] 缺少签名信息,authMap={}", authMap);
|
||||
logger.error("缺少签名信息");
|
||||
return lklNotifyMsg(false, "缺少签名信息");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
logger.error("[拉卡拉支付通知] 缺少out_trade_no字段,body={}", body);
|
||||
logger.error("缺少out_trade_no字段");
|
||||
return lklNotifyMsg(false, "缺少out_trade_no字段");
|
||||
}
|
||||
|
||||
// 查询交易信息
|
||||
logger.debug("[拉卡拉支付通知] 查询交易信息: orderId={}", orderId);
|
||||
QueryWrapper<PayConsumeTrade> tradeQueryWrapper = new QueryWrapper<>();
|
||||
tradeQueryWrapper.eq("order_id", orderId);
|
||||
PayConsumeTrade trade_row_tmp = payConsumeTradeService.findOne(tradeQueryWrapper);
|
||||
@ -1425,32 +1397,25 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
String orderSubject = trade_row_tmp != null ? trade_row_tmp.getTrade_title() : "";
|
||||
Integer userId = trade_row_tmp != null ? trade_row_tmp.getBuyer_id() : 0;
|
||||
|
||||
logger.debug("[拉卡拉支付通知] 交易信息查询完成: storeId={} userId={}", payment_store_id, userId);
|
||||
|
||||
// 更新交易记录的 原支付交易对应的微信订单号 transaction_id
|
||||
if (trade_row_tmp != null && StrUtil.isNotBlank(accTradeNo)) {
|
||||
logger.debug("[拉卡拉支付通知] 更新交易记录的微信订单号: tradeId={} accTradeNo={}",
|
||||
trade_row_tmp.getConsume_trade_id(), accTradeNo);
|
||||
PayConsumeTrade payConsumeTradeUpd = new PayConsumeTrade();
|
||||
payConsumeTradeUpd.setConsume_trade_id(trade_row_tmp.getConsume_trade_id()).setTransaction_id(accTradeNo);
|
||||
payConsumeTradeService.updateTradeByPrimaryKey(payConsumeTradeUpd);
|
||||
}
|
||||
|
||||
// 查询支付渠道
|
||||
logger.debug("[拉卡拉支付通知] 查询支付渠道: channelCode=lakala");
|
||||
QueryWrapper<PayPaymentChannel> channelQueryWrapper = new QueryWrapper<>();
|
||||
channelQueryWrapper.eq("payment_channel_code", "lakala");
|
||||
PayPaymentChannel payPaymentChannel = payPaymentChannelService.findOne(channelQueryWrapper);
|
||||
|
||||
if (payPaymentChannel == null) {
|
||||
logger.error("[拉卡拉支付通知] 支付渠道不存在: channelCode=lakala");
|
||||
logger.error("支付渠道不存在");
|
||||
return lklNotifyMsg(false, "支付渠道不存在");
|
||||
}
|
||||
Integer payment_channel_id = payPaymentChannel.getPayment_channel_id();
|
||||
logger.debug("[拉卡拉支付通知] 支付渠道查询完成: channelId={}", payment_channel_id);
|
||||
|
||||
// 插入充值记录
|
||||
logger.debug("[拉卡拉支付通知] 创建充值记录");
|
||||
PayConsumeDeposit payConsumeDeposit = createNotify(params, payPaymentChannel);
|
||||
payConsumeDeposit.setOrder_id(orderId);
|
||||
payConsumeDeposit.setStore_id(payment_store_id); // 所属店铺
|
||||
@ -1460,89 +1425,47 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
payConsumeDeposit.setDeposit_body(orderSubject);
|
||||
payConsumeDeposit.setUser_id(userId);
|
||||
|
||||
// 设置拉卡拉相关参数
|
||||
String merchantNo = lklNotifyRespJSON.getStr("merchant_no");
|
||||
lklNotifyRespJSON.set("out_separate_no", orderId);// 默认非合单主单订单号
|
||||
lklNotifyRespJSON.set("lkl_sub_trade_no", lklNotifyRespJSON.getStr("trade_no"));// 默认非合单主单交易号
|
||||
lklNotifyRespJSON.set("lkl_sub_log_no", lklNotifyRespJSON.getStr("log_no")); // 默认非合单主单的对账流水号
|
||||
lklNotifyRespJSON.set("split_amt", lklNotifyRespJSON.getStr("total_amount")); // 默认非合单主单支付金额
|
||||
|
||||
logger.debug("[拉卡拉支付通知] 基础参数设置完成: out_separate_no={} lkl_sub_trade_no={} lkl_sub_log_no={} split_amt={}",
|
||||
lklNotifyRespJSON.getStr("out_separate_no"),
|
||||
lklNotifyRespJSON.getStr("lkl_sub_trade_no"),
|
||||
lklNotifyRespJSON.getStr("lkl_sub_log_no"),
|
||||
lklNotifyRespJSON.getStr("split_amt"));
|
||||
|
||||
// 拉卡拉订单合单信息
|
||||
if (StrUtil.isNotBlank(outSplitRspInfos)) {
|
||||
logger.debug("[拉卡拉支付通知] 处理合单信息");
|
||||
// [{"sub_trade_no":"20250830110113130266250034401288","merchant_no":"822584059990FYP","amount":"1","settle_type":"0","sub_log_no":"66250034401288","out_sub_trade_no":"DF-DD-20250830-21","term_no":"N5811590"},{"sub_trade_no":"20250830110113130266250034401289","merchant_no":"8226330541100GU","amount":"1","settle_type":"0","sub_log_no":"66250034401289","out_sub_trade_no":"ORD-DD-20250830-21","term_no":"N5817779"}]
|
||||
payConsumeDeposit.setLkl_combine_params(outSplitRspInfos);
|
||||
|
||||
Pair<String, String> subTradeNos = getLklSubTradeNo(outSplitRspInfos);
|
||||
if (subTradeNos != null) {
|
||||
// 商品子订单号
|
||||
payConsumeDeposit.setOrd_sub_trade_no(subTradeNos.getFirst());
|
||||
// 商品运费子订单号
|
||||
payConsumeDeposit.setDf_sub_trade_no(subTradeNos.getSecond());
|
||||
logger.debug("[拉卡拉支付通知] 子订单号解析完成: ord={} df={}",
|
||||
subTradeNos.getFirst(), subTradeNos.getSecond());
|
||||
}
|
||||
|
||||
// 获取拉卡拉合单商品子订单信息
|
||||
cn.hutool.json.JSONObject goodsOrderInfo = CommonService.getLklCombineSplitRespInfo(merchantNo, outSplitRspInfos, false);
|
||||
if (goodsOrderInfo != null) {
|
||||
lklNotifyRespJSON.set("out_separate_no", goodsOrderInfo.getStr("out_sub_trade_no"));// 合单商品子订单号
|
||||
lklNotifyRespJSON.set("lkl_sub_trade_no", goodsOrderInfo.getStr("sub_trade_no")); // 合单商品子订单的流水号
|
||||
lklNotifyRespJSON.set("lkl_sub_log_no", goodsOrderInfo.getStr("sub_log_no")); // 合单商品子订单的流水号
|
||||
lklNotifyRespJSON.set("split_amt", goodsOrderInfo.getStr("amount")); // 合单子商品订单支付金额
|
||||
|
||||
logger.debug("[拉卡拉支付通知] 合单信息更新完成: out_separate_no={} lkl_sub_trade_no={} lkl_sub_log_no={} split_amt={}",
|
||||
lklNotifyRespJSON.getStr("out_separate_no"),
|
||||
lklNotifyRespJSON.getStr("lkl_sub_trade_no"),
|
||||
lklNotifyRespJSON.getStr("lkl_sub_log_no"),
|
||||
lklNotifyRespJSON.getStr("split_amt"));
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否联合支付
|
||||
logger.debug("[拉卡拉支付通知] 查询联合支付信息: orderId={}", orderId);
|
||||
PayConsumeTradeCombine tradeCombine = payConsumeTradeCombineService.get(orderId);
|
||||
|
||||
TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
|
||||
try {
|
||||
logger.debug("[拉卡拉支付通知] 开始事务处理");
|
||||
|
||||
// 修改 拉卡拉的订单记录 shop_order_lkl
|
||||
logger.debug("[拉卡拉支付通知] 调用shopService更新拉卡拉订单记录");
|
||||
shopService.lklPayNotifyUpdateShopOrderLkl(lklNotifyRespJSON);
|
||||
log.debug("[拉卡拉支付通知] 拉卡拉订单记录更新完成");
|
||||
|
||||
if (tradeCombine != null && StrUtil.isNotBlank(tradeCombine.getOrder_ids())) {
|
||||
logger.debug("[拉卡拉支付通知] 处理联合支付: combinedOrderIds={}", tradeCombine.getOrder_ids());
|
||||
payConsumeDeposit.setOrder_id(tradeCombine.getOrder_ids());
|
||||
}
|
||||
|
||||
// 注:重要,支付完成接口调用
|
||||
log.debug("[拉卡拉支付通知] 调用支付完成处理接口");
|
||||
if (!payConsumeDepositService.processDeposit(payConsumeDeposit, BigDecimal.ZERO, BigDecimal.ZERO,
|
||||
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)) {
|
||||
logger.error("[拉卡拉支付通知][processDeposit]处理订单数据失败!");
|
||||
log.error("[processDeposit]处理订单数据失败!");
|
||||
return lklNotifyMsg(false, "支付失败!");
|
||||
}
|
||||
log.debug("[拉卡拉支付通知] 支付完成处理接口调用成功");
|
||||
|
||||
transactionManager.commit(transactionStatus);
|
||||
logger.info("[拉卡拉支付通知] 事务提交成功,支付处理完成: orderId={}", orderId);
|
||||
} catch (Exception e) {
|
||||
transactionManager.rollback(transactionStatus);
|
||||
logger.error("[拉卡拉支付通知] 事务处理出错,已回滚: orderId={}", orderId, e);
|
||||
log.error("接收拉卡拉支付异步通知出错:{}", e);
|
||||
throw new ApiException(e.getMessage());
|
||||
}
|
||||
|
||||
return lklNotifyMsg(true, "执行成功");
|
||||
} catch (Exception e) {
|
||||
logger.error("[拉卡拉支付通知] 通知处理发生异常", e);
|
||||
logger.error("通知处理发生异常:{}", e.getMessage(), e);
|
||||
return lklNotifyMsg(false, "通知处理发生异常!");
|
||||
}
|
||||
}
|
||||
@ -1977,13 +1900,13 @@ public class PayUserPayServiceImpl extends BaseServiceImpl<PayUserPayMapper, Pay
|
||||
}
|
||||
|
||||
// 6. 根据前缀分类处理
|
||||
if (outSubTradeNo.startsWith(CommonConstant.Sep_GoodsFee_Prefix)) {
|
||||
if (outSubTradeNo.startsWith("ORD-")) {
|
||||
// 处理商品订单
|
||||
if (productSubTradeNo != null) {
|
||||
logger.warn("检测到重复的商品订单子流水号:{}", outSubTradeNo);
|
||||
}
|
||||
productSubTradeNo = item.getStr("sub_trade_no");
|
||||
} else if (outSubTradeNo.startsWith(CommonConstant.Sep_DeliveryFee_Prefix)) {
|
||||
} else if (outSubTradeNo.startsWith("DF-")) {
|
||||
// 处理运费订单
|
||||
if (shippingSubTradeNo != null) {
|
||||
logger.warn("检测到重复的运费子流水号:{}", outSubTradeNo);
|
||||
|
||||
@ -131,26 +131,25 @@
|
||||
<artifactId>restful-sdk</artifactId>
|
||||
<version>1.0.0.6</version>
|
||||
</dependency>
|
||||
<!-- <!– JavaCV库 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>javacv</artifactId>-->
|
||||
<!-- <version>1.5.6</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <!– JavaCV库 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>javacv-platform</artifactId>-->
|
||||
<!-- <version>1.5.6</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <!– FFmpeg平台依赖 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.bytedeco</groupId>-->
|
||||
<!-- <artifactId>ffmpeg-platform</artifactId>-->
|
||||
<!-- <version>4.4-1.5.6</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- JavaCV库 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
<!-- 引入常用windows和linux平台 其他平台用到时在引入 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<!-- rabbitMQ消息队列 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -273,11 +272,6 @@
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
|
||||
<dependency>
|
||||
@ -330,21 +324,6 @@
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<dependencies>
|
||||
<!-- 开发环境使用多平台依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<!--开发环境 -->
|
||||
<profile>
|
||||
@ -355,22 +334,6 @@
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<dependencies>
|
||||
<!-- 开发环境使用多平台依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</profile>
|
||||
<!--测试环境 -->
|
||||
<profile>
|
||||
@ -378,22 +341,6 @@
|
||||
<properties>
|
||||
<profiles.active>test</profiles.active>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- 开发环境使用多平台依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</profile>
|
||||
<!--uat环境 -->
|
||||
<profile>
|
||||
@ -401,22 +348,6 @@
|
||||
<properties>
|
||||
<profiles.active>uat</profiles.active>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- 开发环境使用多平台依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</profile>
|
||||
<!--生产环境 -->
|
||||
<profile>
|
||||
@ -424,24 +355,6 @@
|
||||
<properties>
|
||||
<profiles.active>prod</profiles.active>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- 生产环境仅包含Linux平台依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Linux平台的FFmpeg -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>4.4-1.5.6</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@ -478,12 +391,10 @@
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.spotify</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
|
||||
@ -39,7 +39,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -240,8 +239,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (yestodayOrderNum.getOrderNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (todayOrderNum.getOrderNum().subtract(yestodayOrderNum.getOrderNum())).divide(yestodayOrderNum.getOrderNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (todayOrderNum.getOrderNum().subtract(yestodayOrderNum.getOrderNum())).divide(yestodayOrderNum.getOrderNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -317,8 +316,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -371,8 +370,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -424,8 +423,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -484,8 +483,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -565,8 +564,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
@Service
|
||||
public class AnalyticsProductServiceImpl implements AnalyticsProductService {
|
||||
@ -52,8 +51,8 @@ public class AnalyticsProductServiceImpl implements AnalyticsProductService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -92,8 +91,8 @@ public class AnalyticsReturnServiceImpl implements AnalyticsReturnService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -151,8 +150,8 @@ public class AnalyticsReturnServiceImpl implements AnalyticsReturnService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -206,8 +205,8 @@ public class AnalyticsReturnServiceImpl implements AnalyticsReturnService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -288,8 +287,8 @@ public class AnalyticsReturnServiceImpl implements AnalyticsReturnService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ -53,8 +52,8 @@ public class AnalyticsStoreServiceImpl implements AnalyticsStoreService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (yestodayRegUser.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (todayRegUser.getNum().subtract(yestodayRegUser.getNum())).divide(yestodayRegUser.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (todayRegUser.getNum().subtract(yestodayRegUser.getNum())).divide(yestodayRegUser.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -114,8 +113,8 @@ public class AnalyticsStoreServiceImpl implements AnalyticsStoreService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preRegNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentRegNum.getNum().subtract(preRegNum.getNum())).divide(preRegNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@ -60,8 +59,8 @@ public class AnalyticsSysServiceImpl implements AnalyticsSysService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (yestodayVisits.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (todayVisits.getNum().subtract(yestodayVisits.getNum())).divide(yestodayVisits.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (todayVisits.getNum().subtract(yestodayVisits.getNum())).divide(yestodayVisits.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -106,8 +105,8 @@ public class AnalyticsSysServiceImpl implements AnalyticsSysService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -145,8 +144,8 @@ public class AnalyticsSysServiceImpl implements AnalyticsSysService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -208,8 +207,8 @@ public class AnalyticsSysServiceImpl implements AnalyticsSysService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -271,8 +270,8 @@ public class AnalyticsSysServiceImpl implements AnalyticsSysService {
|
||||
// 计算日环比 日环比 = (当日数据 - 前一日数据) / 前一日数据 * 100%
|
||||
BigDecimal daym2m = BigDecimal.ZERO;
|
||||
if (preProductNum.getNum().compareTo(BigDecimal.ZERO) != 0) {
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, RoundingMode.HALF_UP);
|
||||
//.multiply(new BigDecimal(100));
|
||||
daym2m = (currentProductNum.getNum().subtract(preProductNum.getNum())).divide(preProductNum.getNum(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//.multiply(new BigDecimal("100"));
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ public class ShopBaseStoreCategoryAdminController {
|
||||
return CommonResult.failed(I18nUtil._("分成比例不能小于94"));
|
||||
}
|
||||
|
||||
if (shopBaseStoreCategory.getSplit_ratio().compareTo(new BigDecimal(100)) > 0) {
|
||||
if (shopBaseStoreCategory.getSplit_ratio().compareTo(new BigDecimal("100")) > 0) {
|
||||
return CommonResult.failed(I18nUtil._("分成比例不能大于100"));
|
||||
}
|
||||
|
||||
|
||||
@ -11,8 +11,6 @@ import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
import com.suisung.mall.shop.base.mapper.ShopBaseCrontabMapper;
|
||||
import com.suisung.mall.shop.base.service.ShopBaseCrontabService;
|
||||
import com.suisung.mall.shop.components.quartz.service.QuartzService;
|
||||
import com.suisung.mall.shop.components.quartz.service.impl.QuartzServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -26,16 +24,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @author Xinze
|
||||
* @since 2021-08-16
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabMapper, ShopBaseCrontab> implements ShopBaseCrontabService {
|
||||
|
||||
@Autowired
|
||||
private QuartzService quartzService;
|
||||
|
||||
private final String JOB_NAME_PREFIX = "JOB_";
|
||||
private final String TRIGGER_NAME_PREFIX = "TRIGGER_";
|
||||
private final String JOB_GROUP_NAME = "DEFAULT_JOB_GROUP";
|
||||
private final String TRIGGER_GROUP_NAME = "DEFAULT_TRIGGER_GROUP";
|
||||
@Autowired
|
||||
private QuartzService quartzService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@ -50,7 +48,7 @@ public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabM
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
if (CheckUtil.isNotEmpty(crontab_enable) && crontab_enable == 1) {
|
||||
if (CheckUtil.isNotEmpty(crontab_enable)) {
|
||||
addJob(shopBaseCrontab);
|
||||
}
|
||||
} else {
|
||||
@ -60,26 +58,9 @@ public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabM
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
try {
|
||||
// 先尝试删除已存在的任务(如果存在)
|
||||
quartzService.deleteJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME);
|
||||
} catch (Exception e) {
|
||||
// 删除失败记录日志但不中断操作
|
||||
log.warn("删除旧任务时发生异常: 任务ID={}", crontab_id, e);
|
||||
}
|
||||
|
||||
// 如果任务启用,则添加新任务
|
||||
if (crontab_enable != null && crontab_enable == 1) {
|
||||
try {
|
||||
addJob(shopBaseCrontab);
|
||||
} catch (Exception e) {
|
||||
log.error("添加新任务时发生异常: 任务ID={}", crontab_id, e);
|
||||
// 如果添加失败,尝试从数据库同步任务
|
||||
boolean syncResult = syncSingleCrontabToScheduler(crontab_id);
|
||||
if (!syncResult) {
|
||||
throw new ApiException("添加定时任务失败,且同步任务也失败", e);
|
||||
}
|
||||
}
|
||||
quartzService.deleteJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME);
|
||||
if (crontab_enable == 1) {
|
||||
addJob(shopBaseCrontab);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,13 +72,7 @@ public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabM
|
||||
public boolean removeCrontab(String crontab_id) {
|
||||
boolean flag = remove(crontab_id);
|
||||
if (flag) {
|
||||
try {
|
||||
quartzService.deleteJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME);
|
||||
} catch (Exception e) {
|
||||
// 删除失败时,尝试从数据库同步确保一致性
|
||||
log.warn("删除任务时发生异常: 任务ID={}", crontab_id, e);
|
||||
// 即使删除失败也继续执行,避免阻塞业务流程
|
||||
}
|
||||
quartzService.deleteJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@ -109,19 +84,10 @@ public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabM
|
||||
*/
|
||||
@Override
|
||||
public void addJob(ShopBaseCrontab shopBaseCrontab) {
|
||||
try {
|
||||
String crontab_file = shopBaseCrontab.getCrontab_file();
|
||||
Integer crontab_id = shopBaseCrontab.getCrontab_id();
|
||||
String cron = getCron(shopBaseCrontab);
|
||||
quartzService.addJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME, TRIGGER_NAME_PREFIX + crontab_id, TRIGGER_GROUP_NAME, cron, crontab_file);
|
||||
} catch (Exception e) {
|
||||
log.error("添加定时任务失败,尝试从数据库同步: 任务ID={}", shopBaseCrontab.getCrontab_id(), e);
|
||||
// 如果添加失败,尝试从数据库同步任务
|
||||
boolean syncResult = syncSingleCrontabToScheduler(shopBaseCrontab.getCrontab_id());
|
||||
if (!syncResult) {
|
||||
throw new ApiException("添加定时任务失败,且同步任务也失败", e);
|
||||
}
|
||||
}
|
||||
String crontab_file = shopBaseCrontab.getCrontab_file();
|
||||
Integer crontab_id = shopBaseCrontab.getCrontab_id();
|
||||
String cron = getCron(shopBaseCrontab);
|
||||
quartzService.addJob(JOB_NAME_PREFIX + crontab_id, JOB_GROUP_NAME, TRIGGER_NAME_PREFIX + crontab_id, TRIGGER_GROUP_NAME, cron, crontab_file);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,60 +111,12 @@ public class ShopBaseCrontabServiceImpl extends BaseServiceImpl<ShopBaseCrontabM
|
||||
throw new ApiException(I18nUtil._("每周和每月不能同时选择!"));
|
||||
}
|
||||
|
||||
StringBuilder cron = new StringBuilder();
|
||||
String space = " ";
|
||||
|
||||
return "0" + space + crontab_minute + space + crontab_hour + space + crontab_day + space + crontab_month + space + crontab_week;
|
||||
}
|
||||
cron.append("0").append(space).append(crontab_minute).append(space).append(crontab_hour).append(space).append(crontab_day).append(space).append(crontab_month).append(space).append(crontab_week);
|
||||
|
||||
/**
|
||||
* 从数据库同步单个任务到调度器
|
||||
*
|
||||
* @param crontabId 任务ID
|
||||
* @return 是否同步成功
|
||||
*/
|
||||
public boolean syncSingleCrontabToScheduler(Integer crontabId) {
|
||||
try {
|
||||
// 从数据库获取任务信息
|
||||
ShopBaseCrontab crontab = getById(crontabId);
|
||||
if (crontab == null) {
|
||||
log.warn("未找到ID为{}的定时任务", crontabId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查任务是否启用
|
||||
if (crontab.getCrontab_enable() == null || crontab.getCrontab_enable() != 1) {
|
||||
log.info("任务ID为{}的定时任务未启用,无需同步到调度器", crontabId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 构造任务和触发器名称
|
||||
String jobName = JOB_NAME_PREFIX + crontabId;
|
||||
String jobGroup = JOB_GROUP_NAME;
|
||||
String triggerName = TRIGGER_NAME_PREFIX + crontabId;
|
||||
String triggerGroup = TRIGGER_GROUP_NAME;
|
||||
|
||||
// 生成cron表达式
|
||||
String cron = getCron(crontab);
|
||||
|
||||
// 获取任务类名
|
||||
String jobClass = crontab.getCrontab_file();
|
||||
if (jobClass != null && jobClass.contains(".")) {
|
||||
jobClass = jobClass.substring(0, jobClass.lastIndexOf("."));
|
||||
}
|
||||
|
||||
// 通过QuartzService添加任务
|
||||
if (quartzService instanceof QuartzServiceImpl) {
|
||||
return ((QuartzServiceImpl) quartzService).addOrUpdateJobFromDatabase(
|
||||
jobName, jobGroup, triggerName, triggerGroup, cron, jobClass);
|
||||
} else {
|
||||
// 兼容其他实现
|
||||
quartzService.addJob(jobName, jobGroup, triggerName, triggerGroup, cron, jobClass);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("同步单个定时任务到调度器失败: 任务ID={}", crontabId, e);
|
||||
return false;
|
||||
}
|
||||
return cron.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ public class ShopBaseStateCodeServiceImpl extends BaseServiceImpl<ShopBaseStateC
|
||||
* 根据商品状态码 获取状态名称 (注意在该类内部调用此方法缓存则失效 并且 此表数据如果发生变动则需要靠重启JVM来刷新缓存)
|
||||
* todo 可以优化(这里缓存的是一个字段,不是一条数据)
|
||||
* todo 一般情况此表不会发生变化,如果追求数据一致性,可以考虑使用redis Hash来存储,使用JVM来缓存是更好的选择
|
||||
* <p>
|
||||
*
|
||||
* update 2024-12-14 切换到redis缓存 30秒
|
||||
*
|
||||
* @param code 商品状态码
|
||||
@ -72,12 +72,12 @@ public class ShopBaseStateCodeServiceImpl extends BaseServiceImpl<ShopBaseStateC
|
||||
/**
|
||||
* @param code
|
||||
* @param type 默认值 "state_code_code"
|
||||
* todo 加缓存
|
||||
* todo 加缓存
|
||||
*/
|
||||
@Override
|
||||
public String getCode(Integer code, String type) {
|
||||
if (code != null) {
|
||||
// String code_key = String.format("statecode_%s", code);
|
||||
// String code_key = String.format("statecode-%s", code);
|
||||
Map rows = Convert.toMap(String.class, Object.class, get(code));
|
||||
|
||||
if (rows != null) {
|
||||
|
||||
@ -5,14 +5,13 @@ 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.modules.base.ShopBaseStoreCategory;
|
||||
import com.suisung.mall.common.utils.CheckUtil;
|
||||
import com.suisung.mall.common.utils.CommonUtil;
|
||||
import com.suisung.mall.core.web.service.RedisService;
|
||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
import com.suisung.mall.shop.base.mapper.ShopBaseStoreCategoryMapper;
|
||||
import com.suisung.mall.shop.base.service.ShopBaseStoreCategoryService;
|
||||
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
@ -67,7 +66,7 @@ public class ShopBaseStoreCategoryServiceImpl extends BaseServiceImpl<ShopBaseSt
|
||||
cache_key = cache_key + ":category_is_enable:" + category_is_enable;
|
||||
queryWrapper.eq("category_is_enable", category_is_enable);
|
||||
}
|
||||
Integer pageSize = ObjectUtil.defaultIfNull(getParameter("pageSize", Integer.class), 10);
|
||||
Integer pageSize =ObjectUtil.defaultIfNull(getParameter("pageSize",Integer.class),10) ;
|
||||
cache_key = cache_key + ":" + LANG;
|
||||
|
||||
// 设置cache todo 关闭缓存(修改分类的时候没删除缓存)
|
||||
@ -80,39 +79,39 @@ public class ShopBaseStoreCategoryServiceImpl extends BaseServiceImpl<ShopBaseSt
|
||||
category_rows = Convert.toList(Map.class, categories);
|
||||
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
Map<String, Map> storeLis = new HashMap<>();
|
||||
if (openFindStore) {
|
||||
Map<String,Map> storeLis = new HashMap<>();
|
||||
if(openFindStore){
|
||||
long startTime = System.currentTimeMillis();
|
||||
for (Map category_row : category_rows) {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
|
||||
RequestContextHolder.setRequestAttributes(requestAttributes, true);
|
||||
RequestContextHolder.setRequestAttributes(requestAttributes,true);
|
||||
Integer store_category_id = (Integer) category_row.get("store_category_id");
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
row.put("store_category_id", String.valueOf(store_category_id));
|
||||
row.put("findStore", true);
|
||||
row.put("store_type", "1");
|
||||
Map storeListMap = shopStoreBaseService.getStoreList(1, pageSize, row);
|
||||
row.put("findStore",true);
|
||||
row.put("store_type","1");
|
||||
Map storeListMap= shopStoreBaseService.getStoreList(1, pageSize,row);
|
||||
storeLis.put(String.valueOf(store_category_id), storeListMap);
|
||||
return null;
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.thenRun(() -> {
|
||||
long endTime = System.currentTimeMillis();
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
log.debug("异步调用完成! 总耗时: " + (endTime - startTime) + "ms\n");
|
||||
});
|
||||
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.thenRun(() -> {
|
||||
long endTime = System.currentTimeMillis();
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
log.debug("异步调用完成! 总耗时: "+(endTime - startTime) + "ms\n");
|
||||
});
|
||||
});
|
||||
allOfFuture.join();
|
||||
}
|
||||
|
||||
for (Map category_row : category_rows) {
|
||||
Integer store_category_id = (Integer) category_row.get("store_category_id");
|
||||
List<Map> rs = getCategoryTree(store_category_id, category_is_enable);
|
||||
if (openFindStore) {
|
||||
if(openFindStore){
|
||||
category_row.put("storeList", storeLis.get(String.valueOf(store_category_id)));
|
||||
}
|
||||
category_row.put("id", category_row.get("store_category_id"));
|
||||
@ -123,7 +122,7 @@ public class ShopBaseStoreCategoryServiceImpl extends BaseServiceImpl<ShopBaseSt
|
||||
|
||||
}
|
||||
if (CollUtil.isNotEmpty(category_rows)) {
|
||||
// redisService.set(cache_key, category_rows);
|
||||
// redisService.set(cache_key, category_rows);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,17 +167,17 @@ public class ShopBaseStoreCategoryServiceImpl extends BaseServiceImpl<ShopBaseSt
|
||||
@Override
|
||||
public BigDecimal getStoreCategoryRatio(Integer storeCategoryId) {
|
||||
// 默认分账比例为100%
|
||||
BigDecimal defaultRatio = new BigDecimal(94);
|
||||
BigDecimal defaultRatio = new BigDecimal("100");
|
||||
|
||||
try {
|
||||
// 检查参数是否为空
|
||||
if (CheckUtil.isEmpty(storeCategoryId)) {
|
||||
if (ObjectUtil.isEmpty(storeCategoryId)) {
|
||||
return defaultRatio;
|
||||
}
|
||||
|
||||
// 根据ID获取店铺分类信息
|
||||
ShopBaseStoreCategory shopBaseStoreCategory = get(storeCategoryId);
|
||||
if (shopBaseStoreCategory == null) {
|
||||
if (ObjectUtil.isEmpty(shopBaseStoreCategory)) {
|
||||
return defaultRatio;
|
||||
}
|
||||
|
||||
|
||||
@ -30,12 +30,6 @@ public class IpUtil implements ApplicationRunner {
|
||||
* ip2region搜索器实例
|
||||
*/
|
||||
private static Searcher searcher = null;
|
||||
|
||||
/**
|
||||
* 数据文件加载状态
|
||||
*/
|
||||
private static boolean dataFileLoaded = false;
|
||||
private static String dataFileInfo = "未加载";
|
||||
|
||||
/**
|
||||
* 根据IP地址获取地区信息
|
||||
@ -45,23 +39,18 @@ public class IpUtil implements ApplicationRunner {
|
||||
*/
|
||||
public static String getRegion(String ip) {
|
||||
if (Objects.isNull(searcher)) {
|
||||
log.error("IP2RegionUtils 没有成功加载数据文件. 数据文件状态: {}, 文件信息: {}",
|
||||
dataFileLoaded ? "已加载但searcher为null" : "未加载", dataFileInfo);
|
||||
log.error("IP2RegionUtils 没有成功加载数据文件");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CheckUtil.isEmpty(ip)) {
|
||||
log.debug("传入的IP地址为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String result = searcher.search(ip);
|
||||
log.debug("IP地址 {} 解析成功,结果: {}", ip, result);
|
||||
return result;
|
||||
return searcher.search(ip);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
log.error("IP:{} 解析时发生数组越界异常,可能是数据文件损坏或不兼容. 数据文件状态: {}, 文件信息: {}",
|
||||
ip, dataFileLoaded ? "已加载" : "未加载", dataFileInfo, e);
|
||||
log.error("IP:{} 解析时发生数组越界异常,可能是数据文件损坏或不兼容", ip, e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
String errorMsg = e.getMessage();
|
||||
@ -71,13 +60,7 @@ public class IpUtil implements ApplicationRunner {
|
||||
errorMsg += " -> " + e.getCause().getMessage();
|
||||
}
|
||||
}
|
||||
log.error("IP:{} 格式错误:{}. 数据文件状态: {}, 文件信息: {}",
|
||||
ip, errorMsg, dataFileLoaded ? "已加载" : "未加载", dataFileInfo, e);
|
||||
return null;
|
||||
} catch (Throwable t) {
|
||||
// 捕获所有可能的异常,确保不会传播到调用方
|
||||
log.error("IP:{} 解析时发生未知错误. 数据文件状态: {}, 文件信息: {}",
|
||||
ip, dataFileLoaded ? "已加载" : "未加载", dataFileInfo, t);
|
||||
log.error("IP:{} 格式错误:{}", ip, errorMsg, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -114,24 +97,17 @@ public class IpUtil implements ApplicationRunner {
|
||||
districtVo.setCountry(parts[0] != null ? parts[0] : ""); // 设置国家
|
||||
districtVo.setProvince(parts[2] != null ? parts[2] : ""); // 设置省份
|
||||
districtVo.setCity(parts[3] != null ? parts[3] : ""); // 设置城市
|
||||
|
||||
log.debug("IP地址 {} 解析为地区信息成功. 国家: {}, 省份: {}, 城市: {}",
|
||||
ip, districtVo.getCountry(), districtVo.getProvince(), districtVo.getCity());
|
||||
} else {
|
||||
log.debug("IP:{} 解析结果格式不符合要求,原始数据: {}", ip, ss);
|
||||
return null;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
log.error("解析IP地址 {} 的地区信息时发生数组越界异常,原始数据: {}. 数据文件状态: {}, 文件信息: {}",
|
||||
ip, ss, dataFileLoaded ? "已加载" : "未加载", dataFileInfo, e);
|
||||
log.error("解析IP地址 {} 的地区信息时发生数组越界异常,原始数据: {}", ip, ss, e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("解析IP地址 {} 的地区信息时发生异常: {}. 数据文件状态: {}, 文件信息: {}",
|
||||
ip, e.getMessage(), dataFileLoaded ? "已加载" : "未加载", dataFileInfo, e);
|
||||
log.error("解析IP地址 {} 的地区信息时发生异常: {}", ip, e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
log.debug("IP地址 {} 未解析到地区信息", ip);
|
||||
}
|
||||
|
||||
return districtVo;
|
||||
@ -161,29 +137,16 @@ public class IpUtil implements ApplicationRunner {
|
||||
buffer.flush();
|
||||
byte[] bytes = buffer.toByteArray();
|
||||
|
||||
// 记录数据文件信息
|
||||
dataFileInfo = String.format("文件大小: %d 字节", bytes.length);
|
||||
log.info("读取到 ip2region 数据文件,{}", dataFileInfo);
|
||||
|
||||
inputStream.close();
|
||||
searcher = Searcher.newWithBuffer(bytes);
|
||||
dataFileLoaded = true;
|
||||
|
||||
// 测试搜索器
|
||||
if (searcher != null) {
|
||||
String testResult = searcher.search("8.8.8.8");
|
||||
log.info("成功加载 ip2region 数据文件。测试搜索 8.8.8.8 结果: {}", testResult);
|
||||
} else {
|
||||
log.error("加载 ip2region 数据文件失败,searcher 实例为 null");
|
||||
}
|
||||
log.info("成功加载 ip2region 数据文件。");
|
||||
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
dataFileLoaded = true;
|
||||
log.error("解析IP地址的地区信息时发生数组越界异常。数据文件状态: 已加载, 文件信息: {}", dataFileInfo, e);
|
||||
log.error("解析IP地址的地区信息时发生数组越界异常,原始数据: {}", e);
|
||||
} catch (IOException e) {
|
||||
log.error("加载 ip2region 失败。数据文件状态: 未加载, 文件信息: {}", dataFileInfo, e);
|
||||
log.error("加载 ip2region 失败。", e);
|
||||
} catch (Exception e) {
|
||||
log.error("初始化 ip2region 搜索器失败。数据文件状态: 未加载, 文件信息: {}", dataFileInfo, e);
|
||||
log.error("初始化 ip2region 搜索器失败。", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
package com.suisung.mall.shop.components.quartz.job;
|
||||
|
||||
import com.suisung.mall.common.utils.LogUtil;
|
||||
import com.suisung.mall.shop.config.SpringUtil;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderReturnService;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付宝/微信退款 定时任务
|
||||
*/
|
||||
@ -18,19 +22,20 @@ public class UpdateOrderRefundJob extends QuartzJobBean {
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
String activeProfile = activeProfiles[0];
|
||||
if (!activeProfile.equals("prod")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ShopOrderReturnService orderReturnService = SpringUtil.getBean(ShopOrderReturnService.class);
|
||||
//
|
||||
// // 获取支付宝/微信退款订单
|
||||
// List<String> return_ids = orderReturnService.getOnlineRefundReturnId();
|
||||
// for (String return_id : return_ids) {
|
||||
// if (!orderReturnService.doOnlineRefund(return_id)) {
|
||||
// LogUtil.error(String.format("return_id: %s 原路退回出错", return_id));
|
||||
//
|
||||
// // 处理异常标记
|
||||
// }
|
||||
// }
|
||||
ShopOrderReturnService orderReturnService = SpringUtil.getBean(ShopOrderReturnService.class);
|
||||
|
||||
// 获取支付宝/微信退款订单
|
||||
List<String> return_ids = orderReturnService.getOnlineRefundReturnId();
|
||||
for (String return_id : return_ids) {
|
||||
if (!orderReturnService.doOnlineRefund(return_id)) {
|
||||
LogUtil.error(String.format("return_id: %s 原路退回出错", return_id));
|
||||
|
||||
// 处理异常标记
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
package com.suisung.mall.shop.components.quartz.job;
|
||||
|
||||
import com.suisung.mall.shop.config.SpringUtil;
|
||||
import com.suisung.mall.shop.lakala.service.LakalaApiService;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
|
||||
/**
|
||||
* 分账状态更改补偿 定时任务
|
||||
*/
|
||||
public class UpdateOrderSeparateJob extends QuartzJobBean {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UpdateOrderSeparateJob.class);
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
logger.info("[分账状态修复定时任务] 开始执行");
|
||||
|
||||
try {
|
||||
LakalaApiService lakalaApiService = SpringUtil.getBean(LakalaApiService.class);
|
||||
|
||||
if (lakalaApiService == null) {
|
||||
logger.error("[分账状态修复定时任务] 无法获取LakalaApiService实例");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer processedCount = lakalaApiService.fixedUnSuccessSeparateStatusJob();
|
||||
|
||||
logger.info("[分账状态修复定时任务] 执行完成,共处理 {} 条记录", processedCount);
|
||||
} catch (Exception e) {
|
||||
logger.error("[分账状态修复定时任务] 执行过程中发生异常", e);
|
||||
throw new JobExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -4,19 +4,17 @@ import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.utils.I18nUtil;
|
||||
import com.suisung.mall.shop.components.quartz.service.QuartzService;
|
||||
import org.quartz.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class QuartzServiceImpl implements QuartzService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(QuartzServiceImpl.class);
|
||||
private final String PATH_PREFIX = "com.suisung.mall.shop.components.quartz.job.";
|
||||
@Autowired
|
||||
private Scheduler scheduler;
|
||||
|
||||
private final String PATH_PREFIX = "com.suisung.mall.shop.components.quartz.job.";
|
||||
|
||||
/**
|
||||
* 新增一个定时任务
|
||||
*
|
||||
@ -29,126 +27,24 @@ public class QuartzServiceImpl implements QuartzService {
|
||||
*/
|
||||
@Override
|
||||
public void addJob(String jName, String jGroup, String tName, String tGroup, String cron, String cName) {
|
||||
logger.info("[Quartz] 开始添加定时任务: 任务名称={}, 任务组={}, 触发器名称={}, 触发器组={}, cron表达式={}, 类名={}",
|
||||
jName, jGroup, tName, tGroup, cron, cName);
|
||||
|
||||
// 1. 参数校验
|
||||
if (jName == null || jName.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] 任务名称不能为空: {}", jName);
|
||||
throw new ApiException(I18nUtil._("任务名称不能为空!"));
|
||||
}
|
||||
if (jGroup == null || jGroup.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] 任务组不能为空: {}", jGroup);
|
||||
throw new ApiException(I18nUtil._("任务组不能为空!"));
|
||||
}
|
||||
if (tName == null || tName.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] 触发器名称不能为空: {}", tName);
|
||||
throw new ApiException(I18nUtil._("触发器名称不能为空!"));
|
||||
}
|
||||
if (tGroup == null || tGroup.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] 触发器组不能为空: {}", tGroup);
|
||||
throw new ApiException(I18nUtil._("触发器组不能为空!"));
|
||||
}
|
||||
if (cron == null || cron.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] cron表达式不能为空: {}", cron);
|
||||
throw new ApiException(I18nUtil._("cron表达式不能为空!"));
|
||||
}
|
||||
if (cName == null || cName.trim().isEmpty()) {
|
||||
logger.warn("[Quartz] 任务实现类名称不能为空: {}", cName);
|
||||
throw new ApiException(I18nUtil._("任务实现类名称不能为空!"));
|
||||
}
|
||||
|
||||
// 2. 加载任务类
|
||||
Class<Job> clazz;
|
||||
Class<Job> clazz = null;
|
||||
try {
|
||||
String fullClassName = PATH_PREFIX + cName;
|
||||
logger.debug("[Quartz] 尝试加载任务类: {}", fullClassName);
|
||||
clazz = (Class<Job>) Class.forName(fullClassName);
|
||||
logger.debug("[Quartz] 成功加载任务类: {}", fullClassName);
|
||||
clazz = (Class<Job>) Class.forName(PATH_PREFIX + cName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("[Quartz] 定时任务脚本不存在!类名: {}{}", PATH_PREFIX, cName, e);
|
||||
throw new ApiException(I18nUtil._("定时任务脚本不存在!类名: " + PATH_PREFIX + cName), e);
|
||||
throw new ApiException(I18nUtil._("定时任务脚本不存在!"));
|
||||
}
|
||||
|
||||
try {
|
||||
// 3. 构建任务详情和触发器
|
||||
JobKey jobKey = new JobKey(jName, jGroup);
|
||||
JobDetail jobDetail = JobBuilder.newJob(clazz)
|
||||
.withIdentity(jobKey)
|
||||
.build();
|
||||
|
||||
TriggerKey triggerKey = new TriggerKey(tName, tGroup);
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger()
|
||||
.withIdentity(triggerKey)
|
||||
.startNow()
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
|
||||
.build();
|
||||
|
||||
logger.debug("[Quartz] 构建任务详情和触发器完成: jobKey={}, triggerKey={}", jobKey, triggerKey);
|
||||
|
||||
// 4. 检查任务是否已存在
|
||||
if (scheduler.checkExists(jobKey)) {
|
||||
logger.info("[Quartz] 任务已存在,先删除旧任务: jobKey={}", jobKey);
|
||||
scheduler.deleteJob(jobKey);
|
||||
}
|
||||
|
||||
// 5. 调度任务
|
||||
logger.info("[Quartz] 开始调度任务: jobKey={}, triggerKey={}", jobKey, triggerKey);
|
||||
JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jName, jGroup).build();
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(tName, tGroup).startNow().withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
|
||||
scheduler.start();
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
logger.info("[Quartz] 任务调度成功: jobKey={}, triggerKey={}", jobKey, triggerKey);
|
||||
|
||||
// 6. 启动调度器(如果尚未启动)
|
||||
if (!scheduler.isStarted()) {
|
||||
logger.info("[Quartz] 调度器尚未启动,正在启动...");
|
||||
scheduler.start();
|
||||
logger.info("[Quartz] 调度器启动成功");
|
||||
}
|
||||
} catch (SchedulerException e) {
|
||||
logger.error("[Quartz] 添加定时任务失败!任务名称={}, 任务组={}, 触发器名称={}, 触发器组={}",
|
||||
jName, jGroup, tName, tGroup, e);
|
||||
throw new ApiException(I18nUtil._("添加定时任务失败!"), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("[Quartz] 添加定时任务时发生未知异常!任务名称={}, 任务组={}, 触发器名称={}, 触发器组={}",
|
||||
jName, jGroup, tName, tGroup, e);
|
||||
throw new ApiException(I18nUtil._("添加定时任务失败!"), e);
|
||||
throw new ApiException(I18nUtil._("添加定时任务失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加或更新任务,如果调度器中不存在任务则从数据库获取信息添加
|
||||
*
|
||||
* @param jobName 任务名称
|
||||
* @param jobGroup 任务组
|
||||
* @param triggerName 触发器名称
|
||||
* @param triggerGroup 触发器组
|
||||
* @param dbCron 从数据库获取的cron表达式
|
||||
* @param dbJobClass 从数据库获取的任务类名
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
public boolean addOrUpdateJobFromDatabase(String jobName, String jobGroup, String triggerName,
|
||||
String triggerGroup, String dbCron, String dbJobClass) {
|
||||
logger.info("[Quartz] 尝试从数据库信息添加或更新任务: 任务名称={}, 任务组={}", jobName, jobGroup);
|
||||
|
||||
try {
|
||||
JobKey jobKey = new JobKey(jobName, jobGroup);
|
||||
|
||||
// 检查任务是否已存在
|
||||
if (scheduler.checkExists(jobKey)) {
|
||||
logger.debug("[Quartz] 任务已存在于调度器中: jobKey={}", jobKey);
|
||||
return true; // 任务已存在,无需添加
|
||||
}
|
||||
|
||||
// 任务不存在,从数据库信息创建新任务
|
||||
logger.info("[Quartz] 调度器中不存在任务,从数据库信息创建: jobKey={}", jobKey);
|
||||
addJob(jobName, jobGroup, triggerName, triggerGroup, dbCron, dbJobClass);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("[Quartz] 从数据库信息添加或更新任务失败: 任务名称={}, 任务组={}", jobName, jobGroup, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 暂停定时任务
|
||||
*
|
||||
@ -157,24 +53,10 @@ public class QuartzServiceImpl implements QuartzService {
|
||||
*/
|
||||
@Override
|
||||
public void pauseJob(String jName, String jGroup) {
|
||||
logger.info("[Quartz] 开始暂停定时任务: 任务名称={}, 任务组={}", jName, jGroup);
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(jName, jGroup);
|
||||
|
||||
// 检查任务是否存在,不存在则记录日志并返回,不抛出异常
|
||||
if (!scheduler.checkExists(jobKey)) {
|
||||
logger.info("[Quartz] 任务不存在,无需暂停: jobKey={},可能任务已手动删除或尚未创建", jobKey);
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.pauseJob(jobKey);
|
||||
logger.info("[Quartz] 定时任务暂停成功: jobKey={}", jobKey);
|
||||
} catch (SchedulerException e) {
|
||||
logger.error("[Quartz] 暂停定时任务时发生调度异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使暂停失败也继续执行,避免阻塞业务流程
|
||||
scheduler.pauseJob(JobKey.jobKey(jName, jGroup));
|
||||
} catch (Exception e) {
|
||||
logger.error("[Quartz] 暂停定时任务时发生未知异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使暂停失败也继续执行,避免阻塞业务流程
|
||||
throw new ApiException(I18nUtil._("暂停定时任务失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,24 +68,10 @@ public class QuartzServiceImpl implements QuartzService {
|
||||
*/
|
||||
@Override
|
||||
public void resumeJob(String jName, String jGroup) {
|
||||
logger.info("[Quartz] 开始继续定时任务: 任务名称={}, 任务组={}", jName, jGroup);
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(jName, jGroup);
|
||||
|
||||
// 检查任务是否存在,不存在则记录日志并返回,不抛出异常
|
||||
if (!scheduler.checkExists(jobKey)) {
|
||||
logger.info("[Quartz] 任务不存在,无需继续: jobKey={},可能任务已手动删除或尚未创建", jobKey);
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.resumeJob(jobKey);
|
||||
logger.info("[Quartz] 定时任务继续成功: jobKey={}", jobKey);
|
||||
scheduler.resumeJob(JobKey.jobKey(jName, jGroup));
|
||||
} catch (SchedulerException e) {
|
||||
logger.error("[Quartz] 继续定时任务时发生调度异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使继续失败也继续执行,避免阻塞业务流程
|
||||
} catch (Exception e) {
|
||||
logger.error("[Quartz] 继续定时任务时发生未知异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使继续失败也继续执行,避免阻塞业务流程
|
||||
throw new ApiException(I18nUtil._("继续定时任务失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,30 +83,10 @@ public class QuartzServiceImpl implements QuartzService {
|
||||
*/
|
||||
@Override
|
||||
public void deleteJob(String jName, String jGroup) {
|
||||
logger.info("[Quartz] 开始删除定时任务: 任务名称={}, 任务组={}", jName, jGroup);
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(jName, jGroup);
|
||||
|
||||
// 检查任务是否存在,不存在则记录日志并返回,不抛出异常
|
||||
if (!scheduler.checkExists(jobKey)) {
|
||||
logger.info("[Quartz] 任务不存在,无需删除: jobKey={},可能任务已手动删除或尚未创建", jobKey);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean deleted = scheduler.deleteJob(jobKey);
|
||||
if (deleted) {
|
||||
logger.info("[Quartz] 定时任务删除成功: jobKey={}", jobKey);
|
||||
} else {
|
||||
logger.warn("[Quartz] 定时任务删除失败: jobKey={}", jobKey);
|
||||
}
|
||||
scheduler.deleteJob(JobKey.jobKey(jName, jGroup));
|
||||
} catch (SchedulerException e) {
|
||||
logger.error("[Quartz] 删除定时任务时发生调度异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使删除失败也继续执行,避免阻塞业务流程
|
||||
} catch (Exception e) {
|
||||
logger.error("[Quartz] 删除定时任务时发生未知异常!任务名称={}, 任务组={}", jName, jGroup, e);
|
||||
// 即使删除失败也继续执行,避免阻塞业务流程
|
||||
throw new ApiException(I18nUtil._("删除定时任务失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,51 +1,12 @@
|
||||
package com.suisung.mall.shop.config;
|
||||
|
||||
import com.suisung.mall.core.config.BaseRedisConfig;
|
||||
import com.suisung.mall.shop.order.listener.RedisKeyExpiredListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.listener.PatternTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||
|
||||
/**
|
||||
* Redis相关配置
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RedisConfig extends BaseRedisConfig {
|
||||
@Bean
|
||||
RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,
|
||||
MessageListenerAdapter keyExpiredListener) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.addMessageListener(keyExpiredListener, new PatternTopic("__keyevent@*__:expired"));
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
MessageListenerAdapter keyExpiredListener(RedisKeyExpiredListener redisKeyExpiredListener) {
|
||||
return new MessageListenerAdapter(redisKeyExpiredListener);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisKeyExpiredListener redisKeyExpiredListener() {
|
||||
return new RedisKeyExpiredListener();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 监听Redis键过期事件
|
||||
// */
|
||||
// public static class KeyExpiredListener implements MessageListener {
|
||||
// @Override
|
||||
// public void onMessage(org.springframework.data.redis.connection.Message message,
|
||||
// byte[] pattern) {
|
||||
// String expiredKey = new String(message.getBody());
|
||||
// // 在这里处理过期键的逻辑
|
||||
// log.info("Redis 过期事件监听 Key expired: {}", expiredKey);
|
||||
// // 您可以在这里添加自己的业务逻辑,比如清理相关资源、发送通知等
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
|
||||
if (success && StrUtil.isNotBlank(downloadUrl)) {
|
||||
|
||||
// 1、(电子合同)给商家申请分账功能使用;务必检查是否申请过?申请过忽略
|
||||
Pair<Boolean, String> retPair = lakalaApiService.innerApplyLedgerMer("", false);
|
||||
Pair<Boolean, String> retPair = lakalaApiService.innerApplyLedgerMer(esignContract.getMch_mobile());
|
||||
if (!retPair.getFirst()) {
|
||||
log.error("商家申请分账业务异常:{}", retPair.getSecond());
|
||||
}
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.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.lakala.service.LakalaApiService;
|
||||
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 = "拉卡拉相关接口 - 后端控制器")
|
||||
@RestController
|
||||
@RequestMapping("/admin/shop/lakala")
|
||||
public class LakalaAdminController extends BaseControllerImpl {
|
||||
|
||||
@Resource
|
||||
private LakalaApiService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "查询拉卡拉商户可分账的金额", notes = "查询拉卡拉商户可分账的金额")
|
||||
@RequestMapping(value = "/sacs/queryMchSplitAmt", method = RequestMethod.POST)
|
||||
public CommonResult queryMchCanSplitAmt(@RequestBody JSONObject paramsJSON) {
|
||||
JSONObject resultJSON = lakalaPayService.queryMchCanSplitAmtInner(paramsJSON.getStr("merchantNo"), paramsJSON.getStr("logNo"), paramsJSON.getStr("logDate"));
|
||||
if (resultJSON != null) {
|
||||
return CommonResult.success(resultJSON);
|
||||
}
|
||||
return CommonResult.failed();
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,7 +13,6 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.service.impl.BaseControllerImpl;
|
||||
import com.suisung.mall.shop.lakala.service.LakalaApiService;
|
||||
import com.suisung.mall.shop.lakala.service.LklLedgerEcService;
|
||||
import com.suisung.mall.shop.library.service.LibraryProductService;
|
||||
import com.suisung.mall.shop.message.service.MqMessageService;
|
||||
import com.suisung.mall.shop.message.service.PushMessageService;
|
||||
@ -29,7 +28,6 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -73,13 +71,6 @@ public class LakalaController extends BaseControllerImpl {
|
||||
@Resource
|
||||
private MqMessageService mqMessageService;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private LakalaApiService lakalaApiService;
|
||||
|
||||
@Resource
|
||||
private LklLedgerEcService lklLedgerEcService;
|
||||
|
||||
@ApiOperation(value = "测试案例", notes = "测试案例")
|
||||
@RequestMapping(value = "/testcase", method = RequestMethod.POST)
|
||||
public Object testcase(@RequestBody JSONObject paramsJSON) {
|
||||
@ -114,9 +105,8 @@ public class LakalaController extends BaseControllerImpl {
|
||||
|
||||
// return shopOrderBaseService.sameCityOrderExpireSeconds(10000L);
|
||||
|
||||
// return sfExpressApiService.createSfExpressShop(66, "能辉超市", "桂平市", "广西壮族自治区贵港市桂平市广佰汇超市(桂平店)", "谢能坤", "17777525395", "110.07165452271", "23.369069486251");
|
||||
return sfExpressApiService.createSfExpressShop(66, "能辉超市", "桂平市", "广西壮族自治区贵港市桂平市广佰汇超市(桂平店)", "谢能坤", "17777525395", "110.07165452271", "23.369069486251");
|
||||
|
||||
return lakalaApiService.sacsQuery("8226330541100GU", "20250918770188017227140800").toString();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "批量发送推送消息 - 测试案例", notes = "批量发送推送消息 - 测试案例")
|
||||
@ -141,18 +131,6 @@ public class LakalaController extends BaseControllerImpl {
|
||||
return lakalaPayService.getBankCardBin(paramsJSON.getStr("bankCardNo"));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "发货类交易确认收货通知", notes = "发货类交易确认收货通知 https://o.lakala.com/#/home/document/detail?id=1003")
|
||||
@RequestMapping(value = "/trans/receive/completeNotify", method = RequestMethod.POST)
|
||||
public ResponseEntity<JSONObject> receiveCompleteNotify(HttpServletRequest request) {
|
||||
// 完整地址: https://mall.gpxscs.cn/api/mobile/shop/lakala/trans/receive/completeNotify
|
||||
JSONObject resp = lakalaPayService.receiveCompleteNotify(request);
|
||||
if (resp != null && "SUCCESS".equals(resp.get("code"))) {
|
||||
return ResponseEntity.ok(resp);
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resp);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "商户入网电子合同申请回调通知", notes = "商户入网电子合同申请回调通知")
|
||||
@RequestMapping(value = "/ec/applyNotify", method = RequestMethod.POST)
|
||||
public ResponseEntity<JSONObject> ecApplyNotify(HttpServletRequest request) {
|
||||
@ -164,19 +142,6 @@ public class LakalaController extends BaseControllerImpl {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resp);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "跳转到拉卡拉签署合同链接", notes = "跳转到拉卡拉签署合同链接")
|
||||
@RequestMapping(value = "/sign/ec/{code}", method = RequestMethod.GET)
|
||||
public ModelAndView jumpToSignLklEcLink(@PathVariable Long code) {
|
||||
// 根据 code 值获取结果 URL
|
||||
String resultUrl = lklLedgerEcService.getLklEcResultUrl(code);
|
||||
|
||||
ModelAndView modelAndView = new ModelAndView("sign_lkl_ec");
|
||||
modelAndView.addObject("resultUrl", resultUrl);
|
||||
|
||||
// 返回模板名称,渲染 sign_lkl_ec.html 页面
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "商户分账业务开通申请", notes = "商户分账业务开通申请")
|
||||
@RequestMapping(value = "/ledger/applyLedgerMer", method = RequestMethod.POST)
|
||||
public CommonResult ledgerApplyLedgerMer(@RequestBody JSONObject paramsJSON) {
|
||||
@ -217,24 +182,4 @@ public class LakalaController extends BaseControllerImpl {
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分账结果通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=393
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知")
|
||||
@RequestMapping(value = "/sacs/separateNotify", method = RequestMethod.POST)
|
||||
public ResponseEntity<JSONObject> separateNotify(HttpServletRequest request) {
|
||||
JSONObject resp = lakalaPayService.sacsSeparateNotify(request, "", "");
|
||||
if (resp != null && "SUCCESS".equals(resp.get("code"))) {
|
||||
return ResponseEntity.ok(resp);
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(resp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,19 +8,15 @@
|
||||
|
||||
package com.suisung.mall.shop.lakala.controller.mobile;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.service.impl.BaseControllerImpl;
|
||||
import com.suisung.mall.shop.lakala.service.LakalaApiService;
|
||||
import com.suisung.mall.shop.lakala.service.LklBanksService;
|
||||
import com.suisung.mall.shop.lakala.service.impl.LklTkServiceImpl;
|
||||
import com.suisung.mall.shop.lakala.utils.LakalaUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -31,7 +27,6 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Api(tags = "拉卡拉商户进件控制器")
|
||||
@RestController
|
||||
@RequestMapping("/mobile/shop/lakala/tk")
|
||||
@ -43,10 +38,6 @@ public class LklTkController extends BaseControllerImpl {
|
||||
@Resource
|
||||
private LklBanksService lklBanksService;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private LakalaApiService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "解密拉卡拉进件返回的异步通知", notes = "解密拉卡拉进件返回的异步通知")
|
||||
@RequestMapping(value = "/decode", method = RequestMethod.POST)
|
||||
public String decryptLklTkData(@RequestParam(name = "data") String data,
|
||||
@ -59,33 +50,8 @@ public class LklTkController extends BaseControllerImpl {
|
||||
@ApiOperation(value = "搜索国内银行(支行)分页列表", notes = "搜索国内银行(支行)分页列表,数据包含有效的收款结清行号")
|
||||
@RequestMapping(value = "/bank/search", method = RequestMethod.POST)
|
||||
public CommonResult searchLklBanksPageList(@RequestBody JSONObject paramsJSON) {
|
||||
log.debug("开始搜索国内银行(支行)分页列表,参数: {}", paramsJSON);
|
||||
|
||||
String clearNo = "";
|
||||
String bankCardNo = paramsJSON.getStr("bankCardNo");
|
||||
String keyword = paramsJSON.getStr("keyword");
|
||||
Integer pageNum = paramsJSON.getInt("pageNum");
|
||||
Integer pageSize = paramsJSON.getInt("pageSize");
|
||||
|
||||
log.debug("搜索参数: bankCardNo={}, keyword={}, pageNum={}, pageSize={}", bankCardNo, keyword, pageNum, pageSize);
|
||||
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(bankCardNo)) {
|
||||
log.warn("银行卡号为空,无法获取银行信息");
|
||||
} else {
|
||||
// 通过卡号获取银行信息
|
||||
CommonResult result = lakalaPayService.getBankCardBin(bankCardNo);
|
||||
if (result != null && result.getStatus() == 200L && result.getData() != null) {
|
||||
JSONObject bankInfo = (JSONObject) result.getData();
|
||||
clearNo = bankInfo.getStr("clearingBankCode", bankInfo.getStr("bankCode"));
|
||||
log.debug("获取到银行清算行号: {}", clearNo);
|
||||
} else {
|
||||
log.warn("获取银行卡BIN信息失败,result={}", result);
|
||||
}
|
||||
}
|
||||
|
||||
IPage<Map> list = lklBanksService.pageBranchBanksList("", "", clearNo, 2, keyword, pageNum, pageSize);
|
||||
log.info("搜索国内银行(支行)分页列表完成,结果数量: {}", list != null ? list.getTotal() : 0);
|
||||
// Page<LklBanks> list = lklBanksService.searchBranchBanksPageList(paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize"));
|
||||
IPage<Map> list = lklBanksService.pageBranchBanksList("", "", 2, paramsJSON.getStr("keyword"), paramsJSON.getInt("pageNum"), paramsJSON.getInt("pageSize"));
|
||||
return CommonResult.success(list);
|
||||
}
|
||||
|
||||
|
||||
@ -22,5 +22,5 @@ import java.util.Map;
|
||||
@Repository
|
||||
public interface LklBanksMapper extends BaseMapper<LklBanks> {
|
||||
|
||||
IPage<Map> pageBranchBanksList(Page<Map> page, @Param("bankNo") String bankNo, @Param("branchBankNo") String branchBankNo, @Param("clearNo") String clearNo, @Param("type") Integer type, @Param("keywords") List<String> keywords);
|
||||
IPage<Map> pageBranchBanksList(Page<Map> page, @Param("bankNo") String bankNo, @Param("branchBankNo") String branchBankNo, @Param("type") Integer type, @Param("keywords") List<String> keywords);
|
||||
}
|
||||
|
||||
@ -90,24 +90,10 @@ public interface LakalaApiService {
|
||||
/**
|
||||
* 内部调用:商户分账业务开通申请
|
||||
*
|
||||
* @param merCupNo 商户号
|
||||
* @param forceReApply 如果已申请成功,是否可以重新申请更改?
|
||||
* @param merCupNo
|
||||
* @return
|
||||
*/
|
||||
Pair<Boolean, String> innerApplyLedgerMer(String merCupNo, Boolean forceReApply);
|
||||
|
||||
/**
|
||||
* 发货类交易确认收货通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=1003
|
||||
* 注意:
|
||||
* (1)交易通知接口是交易成功完成后会向 complete_notify_url 这个地址(主扫交易或者主扫合单请求中的complete_notify_url字段)发起交易结果通知。拉卡拉系统通知时,如果商户的应答没有按照以下“响应参考报文”示例返回成功状态时,则系统认为通知失败,系统会通过一定的策略定期重新发起通知。
|
||||
* (2)同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知。
|
||||
* (3)在没有收到拉卡拉支付交易通知的情况下,建议商户主动调用【06查询交易】确认交易状态。
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
JSONObject receiveCompleteNotify(HttpServletRequest request);
|
||||
Pair<Boolean, String> innerApplyLedgerMer(String merCupNo);
|
||||
|
||||
/**
|
||||
* 商户入网电子合同申请回调通知
|
||||
@ -186,39 +172,14 @@ public interface LakalaApiService {
|
||||
*/
|
||||
Pair<Boolean, String> innerDoOrderSeparate(String orderId, String storeId);
|
||||
|
||||
/**
|
||||
* 根据商户号、交易号和收货流水号执行订单分账操作
|
||||
* <p>
|
||||
* 该方法用于处理拉卡拉订单的分账逻辑。在用户确认收货后,系统会根据订单信息执行分账操作,
|
||||
* 将订单金额按照预设比例分配给平台、商家和代理商(如果存在)。
|
||||
* </p>
|
||||
* <p>
|
||||
* 分账操作流程:
|
||||
* 1. 参数校验和订单查询
|
||||
* 2. 检查订单状态(是否已确认收货)
|
||||
* 3. 检查是否已分账,避免重复处理
|
||||
* 4. 计算分账金额
|
||||
* 5. 构建分账请求并发送至拉卡拉
|
||||
* 6. 保存分账结果
|
||||
* </p>
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param receiveTradeNo 收货交易号(对应拉卡拉的trade_no)
|
||||
* @param receiveLogNo 收货流水号(对应拉卡拉的log_no)
|
||||
* @return Pair<Boolean, String> 处理结果对,first为是否成功,second为结果描述信息
|
||||
*/
|
||||
Pair<Boolean, String> innerDoOrderSeparateByMerchantAndLogNo(String lklMerchantNo, String receiveTradeNo, String receiveLogNo);
|
||||
|
||||
/**
|
||||
* 分账结果通知
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=393
|
||||
*
|
||||
* @param request
|
||||
* @param merchantNo 分账方商户号,非空表示是事后补偿
|
||||
* @param separateNo 分账指令流水号,非空表示是事后补偿
|
||||
* @return
|
||||
*/
|
||||
JSONObject sacsSeparateNotify(HttpServletRequest request, String merchantNo, String separateNo);
|
||||
JSONObject sacsSeparateNotify(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* 查询拉卡拉商户可分账的金额
|
||||
@ -238,36 +199,6 @@ public interface LakalaApiService {
|
||||
*/
|
||||
Pair<String, String> queryMchCanSplitAmt(String merchantNo, String logNo, String logDate);
|
||||
|
||||
/**
|
||||
* 查询拉卡拉商户可分账的金额
|
||||
* 参考: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 queryMchCanSplitAmtInner(String merchantNo, String logNo, String logDate);
|
||||
|
||||
|
||||
/**
|
||||
* 分账查询结果
|
||||
* <p>
|
||||
* 用于查询已发起的分账交易的处理结果状态
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=392
|
||||
*
|
||||
* @param merchantNo 分账方商户号
|
||||
* @param separateNo 分账指令流水号
|
||||
* @return 分账结果数据,包含分账状态等信息;查询失败时返回null
|
||||
*/
|
||||
JSONObject sacsQuery(String merchantNo, String separateNo);
|
||||
|
||||
/**
|
||||
* 订单分账撤销
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=390
|
||||
@ -281,11 +212,4 @@ public interface LakalaApiService {
|
||||
*/
|
||||
Boolean sacsSeparateCancel(String merchantNo, String originSeparateNo, String originOutSeparateNo, String outSeparateNo, String totalAmt);
|
||||
|
||||
/**
|
||||
* 更改已经分账的状态(定时任务用途)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Integer fixedUnSuccessSeparateStatusJob();
|
||||
|
||||
}
|
||||
|
||||
@ -32,14 +32,13 @@ public interface LklBanksService {
|
||||
*
|
||||
* @param bankNo 总行号
|
||||
* @param branchBankNo 支行号
|
||||
* @param clearNo 清算行号
|
||||
* @param type 1-店铺地区;2-银行地区
|
||||
* @param keyword 查询关键字,做分词
|
||||
* @param pageNum
|
||||
* @param pageSize
|
||||
* @return
|
||||
*/
|
||||
IPage<Map> pageBranchBanksList(String bankNo, String branchBankNo, String clearNo, Integer type, String keyword, Integer pageNum, Integer pageSize);
|
||||
IPage<Map> pageBranchBanksList(String bankNo, String branchBankNo, Integer type, String keyword, Integer pageNum, Integer pageSize);
|
||||
|
||||
/**
|
||||
* 根据支行号查询支行信息(带省市地区)
|
||||
|
||||
@ -50,12 +50,4 @@ public interface LklLedgerEcService extends IBaseService<LklLedgerEc> {
|
||||
LklLedgerEc getByMchId(Long mchId, String ecStatus, Integer status);
|
||||
|
||||
|
||||
/**
|
||||
* 获取拉卡拉商户签署合同页面URL
|
||||
*
|
||||
* @param mchId
|
||||
* @return
|
||||
*/
|
||||
String getLklEcResultUrl(Long mchId);
|
||||
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ public interface LklLedgerMerReceiverBindService extends IBaseService<LklLedgerM
|
||||
* @param applyId
|
||||
* @return
|
||||
*/
|
||||
LklLedgerMerReceiverBind getMerReceiverByApplyId(String applyId);
|
||||
LklLedgerMerReceiverBind getPlatformByApplyId(String applyId);
|
||||
|
||||
/**
|
||||
* 根据商户编号查询一条代理商绑定记录
|
||||
@ -91,22 +91,4 @@ public interface LklLedgerMerReceiverBindService extends IBaseService<LklLedgerM
|
||||
* @return
|
||||
*/
|
||||
Boolean updateAuditResult(String applyId, String merInnerNo, String merCupNo, String receiverNo, String entrustFileName, String entrustFilePath, String auditStatus, String auditStatusText, String remark);
|
||||
|
||||
/**
|
||||
* 根据入驻号和商户编号查询商户分账接收方绑定记录
|
||||
*
|
||||
* @param mchId 商户ID
|
||||
* @param merCupNo 商户银联编号
|
||||
* @return 删除成功返回true,失败返回false
|
||||
*/
|
||||
List<LklLedgerMerReceiverBind> selectByMchIdAndMerCupNo(Long mchId, String merCupNo);
|
||||
|
||||
/**
|
||||
* 根据入驻编号和商户编号删除商户分账接收方绑定记录
|
||||
*
|
||||
* @param mchId
|
||||
* @param merCupNo
|
||||
* @return
|
||||
*/
|
||||
Boolean delByMchIdAndMerCupNo(Long mchId, String merCupNo);
|
||||
}
|
||||
|
||||
@ -11,9 +11,6 @@ package com.suisung.mall.shop.lakala.service;
|
||||
import com.suisung.mall.common.modules.lakala.LklOrderSeparate;
|
||||
import com.suisung.mall.core.web.service.IBaseService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public interface LklOrderSeparateService extends IBaseService<LklOrderSeparate> {
|
||||
|
||||
/**
|
||||
@ -31,7 +28,7 @@ public interface LklOrderSeparateService extends IBaseService<LklOrderSeparate>
|
||||
* @param outSeparateNo
|
||||
* @return
|
||||
*/
|
||||
LklOrderSeparate getByLogNoAndOutTradeNo(String logNo, String outSeparateNo);
|
||||
LklOrderSeparate getByOutTradeNo(String logNo, String outSeparateNo);
|
||||
|
||||
/**
|
||||
* 根据商户号和平台订单号查询记录
|
||||
@ -50,36 +47,4 @@ public interface LklOrderSeparateService extends IBaseService<LklOrderSeparate>
|
||||
* @return
|
||||
*/
|
||||
Boolean updateRemark(Long id, String remark);
|
||||
|
||||
|
||||
/**
|
||||
* 根据唯一组合键 logNo和 separateNo 修改备注
|
||||
*
|
||||
* @param logNo
|
||||
* @param separateNo
|
||||
* @param remark
|
||||
* @return
|
||||
*/
|
||||
Boolean updateRemark(String logNo, String separateNo, String remark);
|
||||
|
||||
|
||||
/**
|
||||
* 分页获取未成功分账的记录
|
||||
*
|
||||
* @param beginDate 开始时间(必须)
|
||||
* @param endDate 结束时间(可选,为空时默认为当前时间)
|
||||
* @param page 页码(从1开始)
|
||||
* @param size 每页大小
|
||||
* @return 未成功分账的记录列表,参数无效时返回空列表而非null
|
||||
*/
|
||||
List<LklOrderSeparate> getUnSuccessSeparateList(Date beginDate, Date endDate, Integer page, Integer size);
|
||||
|
||||
/**
|
||||
* 判断订单是否已经分账
|
||||
* 记录不存在或 status final_status 不是 SUCCESS 都表示没有分账
|
||||
*
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
Boolean isOrderSeparated(String orderId);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -83,7 +83,6 @@ public class LklBanksServiceImpl extends BaseServiceImpl<LklBanksMapper, LklBank
|
||||
/**
|
||||
* @param bankNo
|
||||
* @param branchBankNo
|
||||
* @param clearNo
|
||||
* @param type
|
||||
* @param keyword
|
||||
* @param pageNum
|
||||
@ -91,9 +90,9 @@ public class LklBanksServiceImpl extends BaseServiceImpl<LklBanksMapper, LklBank
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public IPage<Map> pageBranchBanksList(String bankNo, String branchBankNo, String clearNo, Integer type, String keyword, Integer pageNum, Integer pageSize) {
|
||||
public IPage<Map> pageBranchBanksList(String bankNo, String branchBankNo, Integer type, String keyword, Integer pageNum, Integer pageSize) {
|
||||
Page<Map> page = new Page<>(pageNum, pageSize);
|
||||
return lklBanksMapper.pageBranchBanksList(page, bankNo, branchBankNo, clearNo, type, jiebaUtils.segmentForSearch(keyword));
|
||||
return lklBanksMapper.pageBranchBanksList(page, bankNo, branchBankNo, type, jiebaUtils.segmentForSearch(keyword));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +107,7 @@ public class LklBanksServiceImpl extends BaseServiceImpl<LklBanksMapper, LklBank
|
||||
return null;
|
||||
}
|
||||
|
||||
IPage<Map> list = lklBanksMapper.pageBranchBanksList(new Page<>(1, 1), null, branchBankNo, "", 2, null);
|
||||
IPage<Map> list = lklBanksMapper.pageBranchBanksList(new Page<>(1, 1), null, branchBankNo, 2, null);
|
||||
if (list == null || CollectionUtil.isEmpty(list.getRecords())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -135,19 +135,4 @@ public class LklLedgerEcServiceImpl extends BaseServiceImpl<LklLedgerEcMapper, L
|
||||
return findOne(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拉卡拉商户签署合同页面URL
|
||||
*
|
||||
* @param mchId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getLklEcResultUrl(Long mchId) {
|
||||
LklLedgerEc record = getByMchId(mchId, "", null);
|
||||
if (record != null) {
|
||||
return record.getResult_url();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,78 +14,41 @@ 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.common.utils.CheckUtil;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl<LklLedgerMerReceiverBindMapper, LklLedgerMerReceiverBind> implements LklLedgerMerReceiverBindService {
|
||||
/**
|
||||
* 根据商户编号和接收方编号新增或更新记录
|
||||
* 根据接收方编号新增或更新记录
|
||||
*
|
||||
* @param record 分账绑定记录
|
||||
* @return 操作结果,成功返回true,失败返回false
|
||||
* @param record
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean addOrUpdateByMerCupNoReceiverNo(LklLedgerMerReceiverBind record) {
|
||||
// 参数校验
|
||||
if (record == null || StrUtil.hasBlank(record.getMer_cup_no(), record.getReceiver_no())) {
|
||||
log.warn("分账绑定记录参数校验失败: record为空或关键字段缺失, mer_cup_no={}, receiver_no={}",
|
||||
record != null ? record.getMer_cup_no() : "null",
|
||||
record != null ? record.getReceiver_no() : "null");
|
||||
if (record == null || StrUtil.isBlank(record.getMer_cup_no()) || StrUtil.isBlank(record.getReceiver_no())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构造查询条件
|
||||
QueryWrapper<LklLedgerMerReceiverBind> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("mer_cup_no", record.getMer_cup_no())
|
||||
.eq("receiver_no", record.getReceiver_no())
|
||||
.eq("audit_status", CommonConstant.Enable)
|
||||
.orderByAsc("id");
|
||||
|
||||
// 如果商户ID不为空,则增加商户ID查询条件
|
||||
if (CheckUtil.isNotEmpty(record.getMch_id())) {
|
||||
queryWrapper.eq("mch_id", record.getMch_id());
|
||||
.eq("audit_status", CommonConstant.Enable);
|
||||
List<LklLedgerMerReceiverBind> 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);
|
||||
}
|
||||
|
||||
// 查询已存在的记录
|
||||
LklLedgerMerReceiverBind existsRecord = findOne(queryWrapper);
|
||||
|
||||
// 如果存在有效记录,则更新该记录
|
||||
if (existsRecord != null && existsRecord.getId() != null && existsRecord.getId() > 0) {
|
||||
log.debug("分账绑定记录已存在,执行更新操作: mer_cup_no={}, receiver_no={}, id={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no(), existsRecord.getId());
|
||||
record.setId(existsRecord.getId());
|
||||
boolean updateResult = updateById(record);
|
||||
if (updateResult) {
|
||||
log.info("分账绑定记录更新成功: mer_cup_no={}, receiver_no={}, id={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no(), record.getId());
|
||||
} else {
|
||||
log.error("分账绑定记录更新失败: mer_cup_no={}, receiver_no={}, id={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no(), record.getId());
|
||||
}
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
// 不存在有效记录,则新增记录
|
||||
log.debug("分账绑定记录不存在,执行新增操作: mer_cup_no={}, receiver_no={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no());
|
||||
boolean addResult = add(record);
|
||||
if (addResult) {
|
||||
log.info("分账绑定记录新增成功: mer_cup_no={}, receiver_no={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no());
|
||||
} else {
|
||||
log.error("分账绑定记录新增失败: mer_cup_no={}, receiver_no={}",
|
||||
record.getMer_cup_no(), record.getReceiver_no());
|
||||
}
|
||||
return addResult;
|
||||
return add(record);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +122,7 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl<LklLedg
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public LklLedgerMerReceiverBind getMerReceiverByApplyId(String applyId) {
|
||||
public LklLedgerMerReceiverBind getPlatformByApplyId(String applyId) {
|
||||
if (StrUtil.isBlank(applyId)) {
|
||||
return null;
|
||||
}
|
||||
@ -208,106 +171,50 @@ public class LklLedgerMerReceiverBindServiceImpl extends BaseServiceImpl<LklLedg
|
||||
/**
|
||||
* 更新审核结果
|
||||
*
|
||||
* @param applyId 申请ID
|
||||
* @param merInnerNo 商户内部编号
|
||||
* @param merCupNo 商户银联编号
|
||||
* @param receiverNo 接收方编号
|
||||
* @param entrustFileName 委托文件名
|
||||
* @param entrustFilePath 委托文件路径
|
||||
* @param auditStatus 审核状态
|
||||
* @param auditStatusText 审核状态文本
|
||||
* @param remark 备注
|
||||
* @return 更新成功返回true,失败返回false
|
||||
* @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.hasBlank(applyId, merCupNo, receiverNo, auditStatus)) {
|
||||
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<LklLedgerMerReceiverBind> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("apply_id", applyId);
|
||||
|
||||
// 只有当参数不为空时才更新对应字段
|
||||
updateWrapper.set("mer_inner_no", merInnerNo);
|
||||
updateWrapper.set("mer_cup_no", merCupNo);
|
||||
updateWrapper.set("receiver_no", receiverNo);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据入驻号和商户编号查询商户分账接收方绑定记录
|
||||
*
|
||||
* @param mchId 商户ID
|
||||
* @param merCupNo 商户银联编号
|
||||
* @return 符合条件的商户分账接收方绑定记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<LklLedgerMerReceiverBind> selectByMchIdAndMerCupNo(Long mchId, String merCupNo) {
|
||||
log.debug("开始查询商户分账接收方绑定记录,mchId={}, merCupNo={}", mchId, merCupNo);
|
||||
|
||||
if (CheckUtil.isEmpty(mchId) && StrUtil.isBlank(merCupNo)) {
|
||||
log.warn("查询商户分账接收方绑定记录参数校验失败,mchId和merCupNo不能同时为空");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
QueryWrapper<LklLedgerMerReceiverBind> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("mch_id", mchId)
|
||||
.eq("mer_cup_no", merCupNo);
|
||||
|
||||
List<LklLedgerMerReceiverBind> result = list(queryWrapper);
|
||||
log.debug("查询商户分账接收方绑定记录完成,mchId={}, merCupNo={}, 结果数量={}", mchId, merCupNo, result.size());
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("查询商户分账接收方绑定记录时发生异常,mchId={}, merCupNo={}", mchId, merCupNo, e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据入驻号和商户编号删除商户分账接收方绑定记录
|
||||
*
|
||||
* @param mchId 商户ID
|
||||
* @param merCupNo 商户银联编号
|
||||
* @return 删除成功返回true,失败返回false
|
||||
*/
|
||||
@Override
|
||||
public Boolean delByMchIdAndMerCupNo(Long mchId, String merCupNo) {
|
||||
try {
|
||||
log.debug("开始删除商户分账接收方绑定记录,mchId={}, merCupNo={}", mchId, merCupNo);
|
||||
|
||||
if (CheckUtil.isEmpty(mchId) && StrUtil.isBlank(merCupNo)) {
|
||||
log.warn("删除商户分账接收方绑定记录参数校验失败,mchId和merCupNo不能同时为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
QueryWrapper<LklLedgerMerReceiverBind> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("mch_id", mchId).eq("mer_cup_no", merCupNo);
|
||||
|
||||
boolean removeResult = remove(queryWrapper);
|
||||
|
||||
if (removeResult) {
|
||||
log.info("商户分账接收方绑定记录删除成功,mchId={}, merCupNo={}", mchId, merCupNo);
|
||||
} else {
|
||||
log.warn("商户分账接收方绑定记录删除失败或未找到匹配记录,mchId={}, merCupNo={}", mchId, merCupNo);
|
||||
}
|
||||
|
||||
return removeResult;
|
||||
} catch (Exception e) {
|
||||
log.error("删除商户分账接收方绑定记录时发生异常,mchId={}, merCupNo={}", mchId, merCupNo, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -137,14 +137,14 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl<LklLedgerRecei
|
||||
* 通过平台方(代理商) ID 记录信息转成 Lakala 接收方记录
|
||||
* 平台方一定要获取,如果有代理商也要获取
|
||||
*
|
||||
* @param distributorId 代理商id(非平台Id)
|
||||
* @param platformId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JSONArray buildApplyLedgerReceiverReqParams(Long distributorId) {
|
||||
public JSONArray buildApplyLedgerReceiverReqParams(Long platformId) {
|
||||
List<Long> ids = new ArrayList<>();
|
||||
if (distributorId != null && distributorId > 0) {
|
||||
ids.add(distributorId);
|
||||
if (platformId != null && platformId > 0) {
|
||||
ids.add(platformId);
|
||||
}
|
||||
// 获取平台记录和代理商记录
|
||||
List<EsignPlatformInfo> esignPlatformInfoList = esignPlatformInfoService.getDistributorAndPlatformByIds(ids.toArray(new Long[0]));
|
||||
@ -216,14 +216,14 @@ public class LklLedgerReceiverServiceImpl extends BaseServiceImpl<LklLedgerRecei
|
||||
* 内部调用:申请一个或多个分账接收方(平台方和代理商)
|
||||
*
|
||||
* @param mchId
|
||||
* @param merCupNo 用于标记接收方绑定merCupNo商家
|
||||
* @param distributorId 代理商id(非平台id)
|
||||
* @param merCupNo 用于标记接收方绑定merCupNo商家
|
||||
* @param platformId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean innerApplyLedgerReceiver(Long mchId, String merCupNo, Long distributorId) {
|
||||
public Boolean innerApplyLedgerReceiver(Long mchId, String merCupNo, Long platformId) {
|
||||
// 接收方至少有一个平台方
|
||||
JSONArray buildApplyLedgerReceiverReqParams = buildApplyLedgerReceiverReqParams(distributorId);
|
||||
JSONArray buildApplyLedgerReceiverReqParams = buildApplyLedgerReceiverReqParams(platformId);
|
||||
if (buildApplyLedgerReceiverReqParams == null || buildApplyLedgerReceiverReqParams.isEmpty()) {
|
||||
log.error("先新增平台或代理商信息");
|
||||
return false;
|
||||
|
||||
@ -11,7 +11,6 @@ package com.suisung.mall.shop.lakala.service.impl;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
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.modules.lakala.LklOrderSeparate;
|
||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
import com.suisung.mall.shop.lakala.mapper.LklOrderSeparateMapper;
|
||||
@ -19,8 +18,6 @@ import com.suisung.mall.shop.lakala.service.LklOrderSeparateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@ -57,12 +54,12 @@ public class LklOrderSeparateServiceImpl extends BaseServiceImpl<LklOrderSeparat
|
||||
/**
|
||||
* 根据拉卡拉对账单流水号和平台订单号查询记录
|
||||
*
|
||||
* @param logNo 分账对账流水号
|
||||
* @param outSeparateNo 分账商家的订单号
|
||||
* @param logNo
|
||||
* @param outSeparateNo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public LklOrderSeparate getByLogNoAndOutTradeNo(String logNo, String outSeparateNo) {
|
||||
public LklOrderSeparate getByOutTradeNo(String logNo, String outSeparateNo) {
|
||||
try {
|
||||
if (StrUtil.isBlank(logNo) || StrUtil.isBlank(outSeparateNo)) {
|
||||
log.warn("查询参数为空:logNo={}, outSeparateNo={}", logNo, outSeparateNo);
|
||||
@ -133,121 +130,4 @@ public class LklOrderSeparateServiceImpl extends BaseServiceImpl<LklOrderSeparat
|
||||
lklOrderSeparate.setRemark(remark);
|
||||
return updateById(lklOrderSeparate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据唯一组合键 logNo和 separateNo 修改备注
|
||||
*
|
||||
* @param logNo
|
||||
* @param separateNo
|
||||
* @param remark
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateRemark(String logNo, String separateNo, String remark) {
|
||||
if (StrUtil.isEmpty(logNo) || StrUtil.isEmpty(separateNo) || StrUtil.isEmpty(remark)) {
|
||||
return false;
|
||||
}
|
||||
LklOrderSeparate lklOrderSeparate = new LklOrderSeparate();
|
||||
lklOrderSeparate.setLog_no(logNo);
|
||||
lklOrderSeparate.setSeparate_no(separateNo);
|
||||
lklOrderSeparate.setRemark(remark);
|
||||
return updateById(lklOrderSeparate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取未成功分账的记录
|
||||
*
|
||||
* @param beginDate 开始时间(必须)
|
||||
* @param endDate 结束时间(可选,为空时默认为当前时间)
|
||||
* @param page 页码(从1开始)
|
||||
* @param pageSize 每页大小
|
||||
* @return 未成功分账的记录列表,参数无效时返回空列表而非null
|
||||
*/
|
||||
@Override
|
||||
public List<LklOrderSeparate> getUnSuccessSeparateList(Date beginDate, Date endDate, Integer page, Integer pageSize) {
|
||||
// 1. 参数校验
|
||||
if (beginDate == null) {
|
||||
log.warn("[分页查询未成功分账记录] 开始时间不能为空");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (page == null || page < 1) {
|
||||
log.warn("[分页查询未成功分账记录] 页码必须大于0,当前页码: {}", page);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (pageSize == null || pageSize <= 0) {
|
||||
log.warn("[分页查询未成功分账记录] 页面大小必须大于0,当前大小: {}", pageSize);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 2. 处理结束时间默认值
|
||||
Date actualEndDate = (endDate != null) ? endDate : new Date();
|
||||
|
||||
// 3. 参数合理性校验
|
||||
if (beginDate.after(actualEndDate)) {
|
||||
log.warn("[分页查询未成功分账记录] 开始时间{}不能晚于结束时间{}", beginDate, actualEndDate);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
// 4. 构造查询条件
|
||||
QueryWrapper<LklOrderSeparate> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select("id", "merchant_no", "separate_no", "status", "final_status", "created_at")
|
||||
.ne("status", "SUCCESS")
|
||||
.ne("final_status", "SUCCESS")
|
||||
.ge("created_at", beginDate)
|
||||
.le("created_at", actualEndDate)
|
||||
.orderByDesc("id");
|
||||
|
||||
// 5. 执行分页查询
|
||||
Page<LklOrderSeparate> resultPage = lists(queryWrapper, page, pageSize);
|
||||
List<LklOrderSeparate> result = resultPage.getRecords();
|
||||
|
||||
log.info("[分页查询未成功分账记录] 查询完成,开始时间={},结束时间={},页码={},页面大小={},结果数量={}",
|
||||
beginDate, actualEndDate, page, pageSize, (result != null ? result.size() : 0));
|
||||
|
||||
return result != null ? result : Collections.emptyList();
|
||||
} catch (Exception e) {
|
||||
log.error("[分页查询未成功分账记录] 查询过程中发生异常,开始时间={},结束时间={},页码={},页面大小={}",
|
||||
beginDate, endDate, page, pageSize, e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单是否已经分账完成
|
||||
*
|
||||
* @param orderId 订单ID
|
||||
* @return Boolean true-分账已完成,false-分账未完成或不存在分账记录
|
||||
*/
|
||||
@Override
|
||||
public Boolean isOrderSeparated(String orderId) {
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("订单ID为空,无法判断分账状态");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 直接查询分账成功的记录
|
||||
LklOrderSeparate lklOrderSeparate = findOne(new QueryWrapper<LklOrderSeparate>()
|
||||
.eq("order_id", orderId)
|
||||
.eq("status", "SUCCESS")
|
||||
.eq("final_status", "SUCCESS")
|
||||
.orderByDesc("id"));
|
||||
|
||||
// 如果查询到分账成功的记录,返回true
|
||||
if (lklOrderSeparate == null) {
|
||||
log.debug("订单[{}]分账未完成或不存在分账记录", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.debug("订单[{}]分账已完成", orderId);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("查询订单[{}]分账状态异常", orderId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import com.suisung.mall.common.modules.store.ShopMchEntry;
|
||||
import com.suisung.mall.common.pojo.to.AddressParseResultTO;
|
||||
import com.suisung.mall.common.service.impl.CommonService;
|
||||
import com.suisung.mall.common.utils.AddressUtil;
|
||||
import com.suisung.mall.common.utils.CheckUtil;
|
||||
import com.suisung.mall.common.utils.RestTemplateHttpUtil;
|
||||
import com.suisung.mall.common.utils.UploadUtil;
|
||||
import com.suisung.mall.core.web.service.RedisService;
|
||||
@ -317,54 +318,44 @@ public class LklTkServiceImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* (重要) 请求拉卡拉进件
|
||||
* (重要) 请求拉卡拉进件,
|
||||
* TODO 已经进件过了,一般不涉及更改企业(小微)的信息,可以不要重新进件了
|
||||
* <p>
|
||||
* 参考拉卡拉给的独立文档:2、拓客SAAS商户管理接口(新).docx
|
||||
*
|
||||
* <p>此方法用于向拉卡拉提交商户进件申请,包括完整的商户信息和相关附件。
|
||||
* 已经进件过的商户一般不涉及更改企业(小微)的信息,可以不要重新进件。
|
||||
*
|
||||
* <p>参考拉卡拉给的独立文档:2、拓客SAAS商户管理接口(新).docx
|
||||
*
|
||||
* @param mchId 入驻商家自增Id,不能为空
|
||||
* @return Pair对象,第一个元素表示操作是否成功,第二个元素为操作结果信息
|
||||
* @param mchId 入驻商家自增Id
|
||||
* @return
|
||||
*/
|
||||
public Pair<Boolean, String> registrationMerchant(Long mchId) {
|
||||
logger.info("开始执行拉卡拉商户进件流程,商户ID: {}", mchId);
|
||||
|
||||
// 参数校验
|
||||
if (ObjectUtil.isEmpty(mchId)) {
|
||||
logger.warn("商户进件失败:入驻编号不能为空");
|
||||
return Pair.of(false, "入驻编号不能为空");
|
||||
return Pair.of(false, "入驻商户Id不能为空");
|
||||
}
|
||||
|
||||
String authorization = getLklTkAuthorization();
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
logger.error("商户进件失败:获取拉卡拉token失败");
|
||||
return Pair.of(false, "获取拉卡拉token失败");
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", authorization);
|
||||
header.put("Authorization", getLklTkAuthorization());
|
||||
|
||||
// 获取商家入驻信息,组成请求参数
|
||||
ShopMchEntry shopMchEntry = shopMchEntryService.shopMerchEntryById(mchId);
|
||||
if (ObjectUtil.isEmpty(shopMchEntry)) {
|
||||
logger.warn("商户进件失败:商家入驻信息不存在,商户ID: {}", mchId);
|
||||
return Pair.of(false, "商家入驻信息不存在");
|
||||
}
|
||||
|
||||
if (!CommonConstant.Enable.equals(shopMchEntry.getHas_ec_signed())
|
||||
|| StrUtil.isBlank(shopMchEntry.getContract_download_url())) {
|
||||
logger.warn("商户进件失败:商家未签署合同,商户ID: {}", mchId);
|
||||
return Pair.of(false, "商家先签署合同,再来进件!");
|
||||
}
|
||||
|
||||
// 判断是否已经进件过?进件过,执行下一步操作(进件异步通知的相关操作)
|
||||
// 密集操作:进件审核通过之后,要下一步流程操作:申请分账业务、创建分账接收方
|
||||
// && CheckUtil.isNotEmpty(shopMchEntry.getDistributor_id())
|
||||
if (CommonConstant.Enable.equals(shopMchEntry.getHas_apply_mer())
|
||||
&& !StrUtil.hasBlank(shopMchEntry.getLkl_mer_cup_no(), shopMchEntry.getLkl_term_no())) {
|
||||
|
||||
//密集操作:进件审核通过之后,要下一步流程操作:申请分账业务、创建分账接收方
|
||||
if (CommonConstant.Enable.equals(shopMchEntry.getHas_apply_mer()) && CheckUtil.isNotEmpty(shopMchEntry.getDistributor_id())
|
||||
&& StrUtil.isAllNotBlank(shopMchEntry.getLkl_mer_cup_no(), shopMchEntry.getLkl_term_no())) {
|
||||
// 已经进件过了,执行下一步操作
|
||||
logger.info("商户已进件,执行后续操作,商户ID: {}", mchId);
|
||||
registrationMerchantAfterHook(mchId, shopMchEntry.getLkl_mer_cup_no(), shopMchEntry.getDistributor_id());
|
||||
return Pair.of(true, "请勿重复提交,拉卡拉已进件成功了,准备提交分账业务申请!");
|
||||
}
|
||||
@ -424,7 +415,8 @@ public class LklTkServiceImpl {
|
||||
reqJsonBody.put("accountName", shopMchEntry.getAccount_holder_name()); //结算人账户名称
|
||||
reqJsonBody.put("accountIdCard", larIdCard);//结算⼈(法人或小微个人)证件号码(身份证)
|
||||
|
||||
reqJsonBody.put("settleType", "D1"); //结算类型:0-秒到(不分账);1-次日结算(需要分账)
|
||||
String settleType = String.format("D%d", 1);
|
||||
reqJsonBody.put("settleType", settleType); //结算类型:0-秒到(不分账);1-次日结算(需要分账)
|
||||
reqJsonBody.put("settlementType", "AUTOMATIC"); // 结算方式:MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持)
|
||||
|
||||
// 店铺省市区信息
|
||||
@ -483,87 +475,60 @@ public class LklTkServiceImpl {
|
||||
reqJsonBody.put("bizContent", bizContent);
|
||||
|
||||
// 附件文件相关开始
|
||||
logger.debug("开始处理商户附件文件,商户ID: {}", mchId);
|
||||
JSONArray attachments = new JSONArray();
|
||||
if (Boolean.TRUE.equals(isQy)) {
|
||||
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); // 法人身份证正面
|
||||
logger.debug("成功添加法人身份证正面图片");
|
||||
} else {
|
||||
logger.warn("法人身份证正面图片添加失败");
|
||||
}
|
||||
|
||||
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); // 法人身份证国徽面
|
||||
logger.debug("成功添加法人身份证国徽面图片");
|
||||
} else {
|
||||
logger.warn("法人身份证国徽面图片添加失败");
|
||||
}
|
||||
|
||||
JSONObject BUSINESS_LICENCE = updatePhoto(shopMchEntry.getBiz_license_image(), "BUSINESS_LICENCE", false);
|
||||
if (BUSINESS_LICENCE != null) {
|
||||
attachments.put(BUSINESS_LICENCE); // 营业执照
|
||||
logger.debug("成功添加营业执照图片");
|
||||
} else {
|
||||
logger.warn("营业执照图片添加失败");
|
||||
}
|
||||
|
||||
} else {
|
||||
JSONObject ID_CARD_FRONT = updatePhoto(shopMchEntry.getIndividual_id_images(), "ID_CARD_FRONT", false);
|
||||
if (ID_CARD_FRONT != null) {
|
||||
attachments.put(ID_CARD_FRONT); // 身份证正面
|
||||
logger.debug("成功添加身份证正面图片");
|
||||
} else {
|
||||
logger.warn("身份证正面图片添加失败");
|
||||
}
|
||||
|
||||
JSONObject ID_CARD_BEHIND = updatePhoto(shopMchEntry.getIndividual_id_images2(), "ID_CARD_BEHIND", false);
|
||||
if (ID_CARD_BEHIND != null) {
|
||||
attachments.put(ID_CARD_BEHIND); // 身份证国徽面
|
||||
logger.debug("成功添加身份证国徽面图片");
|
||||
} else {
|
||||
logger.warn("身份证国徽面图片添加失败");
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject SHOP_OUTSIDE_IMG = updatePhoto(shopMchEntry.getFront_facade_image(), "SHOP_OUTSIDE_IMG", false);
|
||||
if (SHOP_OUTSIDE_IMG != null) {
|
||||
attachments.put(SHOP_OUTSIDE_IMG); // 门店门面图片
|
||||
logger.debug("成功添加门店门面图片");
|
||||
} else {
|
||||
logger.warn("门店门面图片添加失败");
|
||||
}
|
||||
|
||||
JSONObject SHOP_INSIDE_IMG = updatePhoto(shopMchEntry.getEnvironment_image(), "SHOP_INSIDE_IMG", false);
|
||||
if (SHOP_INSIDE_IMG != null) {
|
||||
attachments.put(SHOP_INSIDE_IMG); // 门店内部图片
|
||||
logger.debug("成功添加门店内部图片");
|
||||
} else {
|
||||
logger.warn("门店内部图片添加失败");
|
||||
}
|
||||
|
||||
JSONObject BANK_CARD = updatePhoto(shopMchEntry.getBank_image(), "BANK_CARD", false);
|
||||
if (BANK_CARD != null) {
|
||||
attachments.put(BANK_CARD); // 银行卡图片
|
||||
logger.debug("成功添加银行卡图片");
|
||||
} else {
|
||||
logger.warn("银行卡图片添加失败");
|
||||
}
|
||||
reqJsonBody.put("attchments", attachments);
|
||||
logger.debug("商户附件文件处理完成,共添加 {} 个附件", attachments.size());
|
||||
// 附件文件相关结束
|
||||
|
||||
String urlPath = "/sit/htkregistration/merchant";
|
||||
if (Boolean.TRUE.equals(isLklProd)) {
|
||||
if (isLklProd) {
|
||||
// 生产环境启用
|
||||
urlPath = "/registration/merchant";
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("准备提交拉卡拉进件请求,商户ID: {}", mchId);
|
||||
logger.debug("进件请求参数:{}", JSONUtil.toJsonStr(reqJsonBody));
|
||||
logger.info("进件请求参数:{}", JSONUtil.toJsonStr(reqJsonBody));
|
||||
|
||||
JSONObject response = RestTemplateHttpUtil.sendLklPost(buildLklTkUrl(urlPath), header, reqJsonBody, JSONObject.class);
|
||||
logger.debug("拉卡拉进件响应参数:{}", response);
|
||||
@ -573,7 +538,6 @@ public class LklTkServiceImpl {
|
||||
|| !"000000".equals(response.getStr("retCode"))) {
|
||||
|
||||
String errMsg = response.getStr("retMsg") == null ? "提交拉卡拉进件,出现未知错误" : response.getStr("retMsg");
|
||||
logger.error("拉卡拉进件失败,商户ID: {},错误信息: {}", mchId, errMsg);
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "提交拉卡拉进件失败:" + errMsg);
|
||||
return Pair.of(false, "提交拉卡拉进件失败:" + errMsg);
|
||||
|
||||
@ -582,24 +546,19 @@ public class LklTkServiceImpl {
|
||||
// {"merchantNo": "100132349","status": "WAIT_AUDI","state": "1"}
|
||||
JSONObject rawData = response.getJSONObject("rawData"); // 进件这个接口比较特殊,不按照常规返回数据
|
||||
String lklMerInnerNo = rawData.getStr("merchantNo"); //拉卡拉内部商户号
|
||||
|
||||
logger.info("拉卡拉进件成功,商户ID: {},拉卡拉商户号: {}", mchId, lklMerInnerNo);
|
||||
|
||||
// 表中的内部外部商户号暂时都传同一个内部商户号,以便异步通知更改记录
|
||||
Boolean success = shopMchEntryService.updateMerchEntryLklMerCupNo(mchId, CommonConstant.Disable2, lklMerInnerNo, lklMerInnerNo, reqJsonBody.toString(), rawData.toString());
|
||||
if (!Boolean.TRUE.equals(success)) {
|
||||
logger.error("进件成功但更新商户号失败,商户ID: {}", mchId);
|
||||
if (!success) {
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件成功,但更新商户号失败!");
|
||||
return Pair.of(false, "提交进件成功,但更新商户号失败!");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("拉卡拉进件异常,商户ID: {}", mchId, e);
|
||||
logger.error("拉卡拉进件异常:{}", e.getMessage());
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + e.getMessage());
|
||||
return Pair.of(false, "提交拉卡拉进件失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
logger.info("拉卡拉进件提交成功,等待审核,商户ID: {}", mchId);
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING, "提交拉卡拉进件成功,正进一步审核!");
|
||||
return Pair.of(true, "提交拉卡拉进件成功,正进一步审核!");
|
||||
}
|
||||
@ -607,117 +566,91 @@ public class LklTkServiceImpl {
|
||||
/**
|
||||
* (重要)拉卡拉进件异步通知
|
||||
*
|
||||
* <p>处理拉卡拉平台发送的商户进件结果异步通知,包括解密通知数据、更新商户状态等操作。
|
||||
*
|
||||
* @param request HTTP请求对象,包含拉卡拉发送的异步通知数据
|
||||
* @return JSONObject 响应结果,包含处理状态码和消息
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
// @Transactional
|
||||
public JSONObject registrationMerchantNotify(HttpServletRequest request) {
|
||||
logger.info("开始处理拉卡拉进件异步通知");
|
||||
logger.debug("拉卡拉进件异步通知开始");
|
||||
|
||||
try {
|
||||
// 解密请求参数
|
||||
String requestBody = LakalaUtil.getBody(request);
|
||||
logger.debug("拉卡拉进件异步通知原始参数:{}", requestBody);
|
||||
// 解密请求参数
|
||||
String requestBody = LakalaUtil.getBody(request);
|
||||
logger.debug("拉卡拉进件异步通知返回参数:{}", requestBody);
|
||||
|
||||
if (StrUtil.isBlank(requestBody)) {
|
||||
logger.warn("拉卡拉进件异步通知参数为空");
|
||||
return new JSONObject().set("code", "400").set("message", "返回参数为空");
|
||||
}
|
||||
|
||||
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
|
||||
if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) {
|
||||
logger.warn("拉卡拉进件异步通知参数格式有误,无法解析: {}", requestBody);
|
||||
return new JSONObject().set("code", "400").set("message", "参数格式有误,无法解析");
|
||||
}
|
||||
|
||||
String srcData = reqBodyJSON.getStr("data");
|
||||
if (StrUtil.isBlank(srcData)) {
|
||||
logger.warn("拉卡拉进件异步通知关键参数为空值");
|
||||
return new JSONObject().set("code", "400").set("message", "关键参数为空值");
|
||||
}
|
||||
|
||||
// 公钥解密出来的数据
|
||||
logger.debug("开始解密拉卡拉通知数据");
|
||||
String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false);
|
||||
String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData);
|
||||
if (StrUtil.isBlank(data)) {
|
||||
logger.error("拉卡拉进件异步通知数据解密失败");
|
||||
return new JSONObject().set("code", "400").set("message", "数据解密出错!");
|
||||
}
|
||||
|
||||
logger.info("拉卡拉进件异步通知数据解密成功,开始处理业务逻辑");
|
||||
|
||||
// 逻辑处理
|
||||
JSONObject dataJSON = JSONUtil.parseObj(data);
|
||||
String auditStatus = dataJSON.getStr("status");
|
||||
String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号
|
||||
String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号
|
||||
String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号
|
||||
|
||||
logger.debug("解析通知数据完成 - 审核状态: {},外部商户号: {},内部商户号: {},终端号: {}",
|
||||
auditStatus, merCupNo, merInnerNo, termNos);
|
||||
|
||||
// 合并参数校验
|
||||
if (dataJSON.isEmpty() ||
|
||||
StrUtil.isBlank(auditStatus) ||
|
||||
StrUtil.isBlank(merCupNo) ||
|
||||
StrUtil.isBlank(merInnerNo)) {
|
||||
logger.warn("拉卡拉进件异步通知参数解析出错,数据: {}", data);
|
||||
return new JSONObject().set("code", "500").set("message", "参数解析出错");
|
||||
}
|
||||
|
||||
// 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据
|
||||
logger.debug("开始查询商户入驻信息,内部商户号: {}", merInnerNo);
|
||||
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo);
|
||||
if (shopMchEntry == null) {
|
||||
logger.error("拉卡拉进件异步通知:{}内部商户号入驻信息不存在!", merInnerNo);
|
||||
return new JSONObject().put("code", "500").put("message", merInnerNo + "内部商户号入驻信息不存在");
|
||||
}
|
||||
|
||||
Long mchId = shopMchEntry.getId();
|
||||
logger.info("找到商户入驻信息,商户ID: {}", mchId);
|
||||
|
||||
// 校验审核状态
|
||||
logger.debug("校验审核状态: {}", auditStatus);
|
||||
if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) {
|
||||
String remark = dataJSON.getStr("remark");
|
||||
logger.warn("拉卡拉进件审核未通过,审核状态: {},备注: {}", auditStatus, remark);
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + remark);
|
||||
return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误");
|
||||
}
|
||||
|
||||
logger.info("拉卡拉进件审核通过,商户ID: {},开始更新商户信息", mchId);
|
||||
|
||||
// RMK 拉卡拉进价提交成功,边处理周边的数据,边等待审核异步通知
|
||||
|
||||
// 更新已进件成功的商户号和设备号
|
||||
logger.debug("开始更新商户拉卡拉审核状态");
|
||||
Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(
|
||||
merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data);
|
||||
|
||||
if (!Boolean.TRUE.equals(success)) {
|
||||
logger.error("拉卡拉进件审核通过但更新商户号失败,商户ID: {}", mchId);
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件时更新商户号失败");
|
||||
return new JSONObject().set("code", "500").set("message", "更新商户号失败");
|
||||
}
|
||||
|
||||
logger.info("商户拉卡拉审核状态更新成功,商户ID: {}", mchId);
|
||||
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING,
|
||||
"进件、申请分账业务、创建分账接收方均已成功,等待拉卡拉审核分账业务请求!");
|
||||
|
||||
//密集操作:进件审核通过之后,要下一步流程操作:申请分账业务、创建分账接收方
|
||||
logger.info("开始执行进件后续操作,商户ID: {},拉卡拉商户号: {}", mchId, merCupNo);
|
||||
registrationMerchantAfterHook(mchId, merCupNo, shopMchEntry.getDistributor_id());
|
||||
|
||||
logger.info("拉卡拉进件异步通知处理完成,商户ID: {}", mchId);
|
||||
return new JSONObject().set("code", "200").set("message", "处理成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("处理拉卡拉进件异步通知异常", e);
|
||||
return new JSONObject().set("code", "500").set("message", "处理异常:" + e.getMessage());
|
||||
if (StrUtil.isBlank(requestBody)) {
|
||||
return new JSONObject().set("code", "400").set("message", "返回参数为空");
|
||||
}
|
||||
|
||||
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
|
||||
if (reqBodyJSON.isEmpty() || reqBodyJSON.get("data") == null) {
|
||||
return new JSONObject().set("code", "400").set("message", "参数格式有误,无法解析");
|
||||
}
|
||||
|
||||
String srcData = reqBodyJSON.getStr("data");
|
||||
if (StrUtil.isBlank(srcData)) {
|
||||
return new JSONObject().set("code", "400").set("message", "关键参数为空值");
|
||||
}
|
||||
|
||||
// 公钥解密出来的数据
|
||||
String notifyPubKey = LakalaUtil.getResourceFile(notifyPubKeyPath, false, false);
|
||||
String data = LakalaUtil.decryptNotifyData(notifyPubKey, srcData);
|
||||
if (StrUtil.isBlank(data)) {
|
||||
return new JSONObject().set("code", "400").set("message", "数据解密出错!");
|
||||
}
|
||||
|
||||
logger.debug("拉卡拉进件异步通知data解密成功,开始处理逻辑");
|
||||
|
||||
// 逻辑处理
|
||||
JSONObject dataJSON = JSONUtil.parseObj(data);
|
||||
String auditStatus = dataJSON.getStr("status");
|
||||
String merCupNo = dataJSON.getStr("externalCustomerNo"); //拉卡拉外部商户号
|
||||
String merInnerNo = dataJSON.getStr("customerNo"); //拉卡拉内部商户号
|
||||
String termNos = dataJSON.getStr("termNos"); //拉卡拉分配的业务终端号
|
||||
|
||||
// 合并参数校验
|
||||
if (dataJSON.isEmpty() ||
|
||||
StrUtil.isBlank(auditStatus) ||
|
||||
StrUtil.isBlank(merCupNo) ||
|
||||
StrUtil.isBlank(merInnerNo)) {
|
||||
return new JSONObject().set("code", "500").set("message", "参数解析出错");
|
||||
}
|
||||
|
||||
// 给商家入驻表增加拉卡拉的商户号和拉卡拉返回的数据
|
||||
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByMerInnerNo(merInnerNo);
|
||||
if (shopMchEntry == null) {
|
||||
logger.error("拉卡拉进件异步通知:{}内部商户号入驻信息不存在!", merInnerNo);
|
||||
return new JSONObject().put("code", "500").put("message", merInnerNo + "内部商户号入驻信息不存在");
|
||||
}
|
||||
|
||||
Long mchId = shopMchEntry.getId();
|
||||
|
||||
|
||||
// 校验审核状态
|
||||
if (!"SUCCESS".equals(auditStatus) && !"REVIEW_PASS".equals(auditStatus)) {
|
||||
logger.debug("返回的审核状态:{}", auditStatus);
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件失败:" + dataJSON.getStr("remark"));
|
||||
return new JSONObject().set("code", "FAIL").set("message", "返回审核状态有误");
|
||||
}
|
||||
|
||||
// RMK 拉卡拉进价提交成功,边处理周边的数据,边等待审核异步通知
|
||||
|
||||
// 更新已进件成功的商户号和设备号
|
||||
Boolean success = shopMchEntryService.updateMerchEntryLklAuditStatusByLklMerCupNo(
|
||||
merInnerNo, merCupNo, termNos, CommonConstant.Enable, null, data);
|
||||
|
||||
if (!success) {
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, CommonConstant.MCH_APPR_STA_LKL_NOPASS, "进件时更新商户号失败");
|
||||
return new JSONObject().set("code", "500").set("message", "更新商户号失败");
|
||||
}
|
||||
|
||||
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(shopMchEntry.getId(), CommonConstant.MCH_APPR_STA_LKL_PADDING,
|
||||
"进件、申请分账业务、创建分账接收方均已成功,等待拉卡拉审核分账业务请求!");
|
||||
|
||||
//密集操作:进件审核通过之后,要下一步流程操作:申请分账业务、创建分账接收方
|
||||
registrationMerchantAfterHook(mchId, merCupNo, shopMchEntry.getDistributor_id());
|
||||
|
||||
return new JSONObject().set("code", "200").set("message", "处理成功");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -731,7 +664,7 @@ public class LklTkServiceImpl {
|
||||
logger.info("商家进件已成功,下一步申请拉卡拉分账业务,再创建分账接收方!");
|
||||
|
||||
// 重要:给商家申请分账业务;务必检查是否申请过?申请过忽略
|
||||
Pair<Boolean, String> applyRetPair = lakalaApiService.innerApplyLedgerMer(merCupNo, true);
|
||||
Pair<Boolean, String> applyRetPair = lakalaApiService.innerApplyLedgerMer(merCupNo);
|
||||
if (!applyRetPair.getFirst()) {
|
||||
String message = "提交分账业务申请异常:" + applyRetPair.getSecond();
|
||||
shopMchEntryService.updateMerchEntryApprovalByMchId(mchId, null, message);
|
||||
@ -924,44 +857,5 @@ public class LklTkServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject bankList(String areaCode, String bankName) {
|
||||
if (StrUtil.isBlank(areaCode)) {
|
||||
}
|
||||
|
||||
JSONObject header = new JSONObject();
|
||||
header.put("Authorization", getLklTkAuthorization());
|
||||
|
||||
// Base64Utils.encodeToString(file.getBytes());
|
||||
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("areaCode", areaCode);
|
||||
requestBody.put("bankName", bankName);
|
||||
|
||||
String urlPath = "/sit/registration/bank";
|
||||
if (isLklProd) {
|
||||
// 生产环境启用
|
||||
urlPath = "/registration/bank";
|
||||
}
|
||||
|
||||
try {
|
||||
ResponseEntity<JSONObject> updResponse = RestTemplateHttpUtil.sendPostBodyBackEntity(buildLklTkUrl(urlPath), 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", "");
|
||||
} catch (Exception e) {
|
||||
logger.error("上传文件异常:{}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -8,10 +8,7 @@
|
||||
|
||||
package com.suisung.mall.shop.lakala.utils;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.lkl.laop.sdk.Config2;
|
||||
import com.lkl.laop.sdk.LKLSDK;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
@ -35,7 +32,6 @@ import java.security.cert.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
@ -266,9 +262,6 @@ public class LakalaUtil {
|
||||
try {
|
||||
log.debug("拉卡拉 Authorization 内容:{}", authorization);
|
||||
Map<String, String> headerMap = getLakalaAuthorizationMap(authorization);
|
||||
if (headerMap == null) {
|
||||
return false;
|
||||
}
|
||||
String timestamp = headerMap.get("timestamp");
|
||||
String nonceStr = headerMap.get("nonce_str");
|
||||
String signature = headerMap.get("signature");
|
||||
@ -311,12 +304,6 @@ public class LakalaUtil {
|
||||
*/
|
||||
public static Map<String, String> getLakalaAuthorizationMap(String authorization) {
|
||||
Map<String, String> map = new HashMap();
|
||||
if (StrUtil.isBlank(authorization)) {
|
||||
log.error("请求头中无 Authorization 授权信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
authorization = authorization.trim();
|
||||
int bpos = authorization.indexOf(" ");
|
||||
String authType = authorization.substring(0, bpos);
|
||||
@ -478,14 +465,14 @@ public class LakalaUtil {
|
||||
if (passVerifySign) {
|
||||
// 如果不需要验签,直接返回请求体内容
|
||||
String requestBody = getBody(request);
|
||||
log.debug("###{} 异步回调通知返回的数据:{}###", request.getRequestURL(), requestBody);
|
||||
log.debug("###{} 异步回调通知请求过来的参数:{}###", request.getRequestURL(), requestBody);
|
||||
return Pair.of(true, requestBody);
|
||||
}
|
||||
|
||||
// 验签
|
||||
String authorization = request.getHeader("Authorization");
|
||||
String requestBody = getBody(request);
|
||||
log.info("###{} 异步回调通知返回的数据:{}\n authorization参数:{}###", request.getRequestURL(), requestBody, authorization);
|
||||
log.info("###{} 异步回调通知请求过来的参数:{}\n authorization参数:{}###", request.getRequestURL(), requestBody, authorization);
|
||||
|
||||
boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath);
|
||||
if (!checkSuccess) {
|
||||
@ -495,31 +482,4 @@ public class LakalaUtil {
|
||||
|
||||
return Pair.of(true, requestBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建拉卡拉接口公共参数
|
||||
* <p>
|
||||
* 公共参数包括:
|
||||
* - reqTime: 时间戳,格式为yyyyMMddHHmmss
|
||||
* - version: 版本号,固定为1.0.0
|
||||
* - reqId: 请求序列号,使用UUID生成唯一标识
|
||||
*
|
||||
* @return 包含公共参数的JSONObject
|
||||
*/
|
||||
public static JSONObject buildParams() {
|
||||
JSONObject params = new JSONObject();
|
||||
|
||||
// 时间戳,格式为yyyyMMddHHmmss
|
||||
String reqTime = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||
params.set("reqTime", reqTime);
|
||||
|
||||
// 版本号,固定为1.0.0
|
||||
params.set("version", "1.0.0");
|
||||
|
||||
// 请求序列号,使用UUID生成唯一标识并去除横线
|
||||
String reqId = IdUtil.simpleUUID();
|
||||
params.set("reqId", reqId);
|
||||
|
||||
return params;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@ import java.util.stream.Collectors;
|
||||
public class PushMessageServiceImpl implements PushMessageService {
|
||||
|
||||
private static final String appName = "小发同城";
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private UniCloudPushService uniCloudPushService;
|
||||
@ -139,7 +138,7 @@ public class PushMessageServiceImpl implements PushMessageService {
|
||||
|
||||
Pair<Boolean, String> result = uniCloudPushService.sendPushMessageBatch(cidList,
|
||||
appName + "邀请您签署入驻合同",
|
||||
"恭喜您的开店入驻申请已审核通过!请尽快登录小发商家 APP 平台签署电子合同,签署链接24小时内有效(逾期需重新提交申请)。如有疑问请联系客服,感谢您的支持!",
|
||||
"恭喜您的开店入驻申请已审核通过!请尽快登录APP平台签署电子合同,签署链接24小时内有效(逾期需重新提交申请)。如有疑问请联系客服,感谢您的支持!",
|
||||
payload);
|
||||
|
||||
if (!result.getFirst()) {
|
||||
@ -168,7 +167,7 @@ public class PushMessageServiceImpl implements PushMessageService {
|
||||
public void noticeMerchantEmployeeOrderAction(Integer storeId, String orderId, String title, String content, JSONObject payload) {
|
||||
try {
|
||||
List<String> cidList = shopStoreEmployeeService.selectEmployeeGeTuiCidByStoreId(storeId, orderId, null);
|
||||
// log.debug("[订单推送] cid 列表:{}", cidList);
|
||||
log.debug("[订单推送] cid 列表:{}", cidList);
|
||||
// 获取 商家的 cid
|
||||
uniCloudPushService.sendPushMessageBatch(cidList, title, content, payload);
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -38,11 +38,12 @@ import java.util.stream.LongStream;
|
||||
@lombok.extern.slf4j.Slf4j
|
||||
public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMapper, ShopNumberSeq> implements ShopNumberSeqService {
|
||||
|
||||
private final String CACHE_PREFIX = "shop_number_seq:%S";
|
||||
@Autowired
|
||||
private ShopNumberSeqMapper shopNumberSeqMapper;
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
private String CACHE_PREFIX = "shop_number_seq:%S";
|
||||
|
||||
@Autowired
|
||||
private ShopProductSpecItemService shopProductSpecItemService;
|
||||
|
||||
@ -52,10 +53,6 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.printf(IntStream.rangeClosed(1, 1).boxed().collect(Collectors.toList()).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到下一个Id
|
||||
* 方法走到这里会产生串行化,集群部署这里不能使用单机锁
|
||||
@ -68,7 +65,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
public synchronized String createNextSeq(String prefix) {
|
||||
|
||||
String ymd = DateUtil.format(new Date(), "yyyyMMdd");
|
||||
String id = String.format("%s_%s_", prefix, ymd);
|
||||
String id = String.format("%s-%s-", prefix, ymd);
|
||||
ShopNumberSeq shopNumberSeq = this.baseMapper.selectById(id);
|
||||
if (shopNumberSeq == null) {
|
||||
shopNumberSeq = new ShopNumberSeq();
|
||||
@ -79,7 +76,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
}
|
||||
}
|
||||
|
||||
String order_id = String.format("%s_%s_%s", prefix, ymd, shopNumberSeq.getNumber());
|
||||
String order_id = String.format("%s-%s-%s", prefix, ymd, shopNumberSeq.getNumber());
|
||||
shopNumberSeq.setPrefix(id);
|
||||
boolean flag = edit(shopNumberSeq);
|
||||
if (flag) {
|
||||
@ -89,6 +86,7 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 得到下一个Id
|
||||
*
|
||||
@ -130,26 +128,25 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
|
||||
/**
|
||||
* 校验同步数据是否同步完成,就是两个库的主键是否一致
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private void checkPrimaryKey() {
|
||||
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size() > 1;
|
||||
while (!flag) {
|
||||
private void checkPrimaryKey(){
|
||||
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||
while (!flag){
|
||||
try {
|
||||
Thread.sleep(3600);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("checkPrimaryKey枷锁失败--" + e.getMessage());
|
||||
log.error("checkPrimaryKey枷锁失败--"+e.getMessage());
|
||||
break;
|
||||
}
|
||||
flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size() > 1;
|
||||
flag=shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量获取id
|
||||
*
|
||||
* @param seqName
|
||||
* @param batchSize
|
||||
* @return
|
||||
@ -159,8 +156,8 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
if (batchSize <= 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
long number = 0;
|
||||
if (null == redisService.get(String.format(CACHE_PREFIX, seqName))) {
|
||||
long number= 0;
|
||||
if (null==redisService.get(String.format(CACHE_PREFIX, seqName))) {
|
||||
// 1. 获取当前序列值
|
||||
QueryWrapper<ShopNumberSeq> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("prefix", seqName);
|
||||
@ -174,9 +171,9 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
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;
|
||||
}else {
|
||||
int numberCache=(Integer) redisService.get(String.format(CACHE_PREFIX, seqName))+1;
|
||||
number= numberCache;
|
||||
|
||||
}
|
||||
|
||||
@ -190,8 +187,8 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
return LongStream.rangeClosed(start, end).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void batchUpdateSeq(List<ShopNumberSeq> shopNumberSeqList) {
|
||||
int count = 0;
|
||||
public void batchUpdateSeq(List<ShopNumberSeq> shopNumberSeqList){
|
||||
int count=0;
|
||||
for (int i = 0; i < shopNumberSeqList.size(); i++) {
|
||||
shopNumberSeqMapper.myUpdateSeq(shopNumberSeqList.get(i));
|
||||
Long number = shopNumberSeqList.get(i).getNumber();
|
||||
@ -199,24 +196,24 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
this.edit(shopNumberSeqList.get(i));
|
||||
count++;
|
||||
}
|
||||
log.info("更新成功{}条数据", count);
|
||||
}
|
||||
log.info("更新成功{}条数据",count);
|
||||
}
|
||||
|
||||
public void clearKey() {
|
||||
redisService.del(String.format(CACHE_PREFIX, "item_id"));
|
||||
redisService.del(String.format(CACHE_PREFIX, "product_id"));
|
||||
public void clearKey(){
|
||||
redisService.del(String.format(CACHE_PREFIX,"item_id"));
|
||||
redisService.del(String.format(CACHE_PREFIX,"product_id"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void clearKeyStoreItemSepcId() {
|
||||
public void clearKeyStoreItemSepcId(){
|
||||
redisService.del(RedisKey.STOREDATASPECITEMID);
|
||||
}
|
||||
|
||||
public void clearKeyStoreAccountBaseId() {
|
||||
public void clearKeyStoreAccountBaseId(){
|
||||
redisService.del(RedisKey.STOREDATACCOUNTBASEID);
|
||||
}
|
||||
|
||||
public void clearKeyStoreSepcId() {
|
||||
public void clearKeyStoreSepcId(){
|
||||
redisService.del(RedisKey.STOREDATASPECID);
|
||||
}
|
||||
|
||||
@ -224,32 +221,31 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
* 清除缓存,专门给并发使用,防止redis的缓存没有加载
|
||||
*/
|
||||
@Override
|
||||
public void clearRelateGoodsId() {
|
||||
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size() > 1;
|
||||
if (flag) {
|
||||
public void clearRelateGoodsId(){
|
||||
boolean flag = shopNumberSeqMapper.findNumberFromShopBaseAndItem(new ShopNumberSeq()).size()>1;
|
||||
if(flag){
|
||||
return;
|
||||
}
|
||||
List<ShopNumberSeq> shopNumberSeqList = shopNumberSeqMapper.findProductAndImtemId(new ShopNumberSeq());
|
||||
for (ShopNumberSeq shopNumberSeq : shopNumberSeqList) {
|
||||
if (shopNumberSeq.getPrefix().equals("product_id")) {
|
||||
clearCache("product_id", shopNumberSeq.getNumber());
|
||||
List<ShopNumberSeq> 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());
|
||||
if(shopNumberSeq.getPrefix().equals("item_id")){
|
||||
clearCache("item_id",shopNumberSeq.getNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 刷新缓存
|
||||
*/
|
||||
private void clearCache(String seqName, long number) {
|
||||
private void clearCache(String seqName,long number){
|
||||
QueryWrapper<ShopNumberSeq> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("prefix", seqName);
|
||||
ShopNumberSeq seq = getById(seqName);
|
||||
if (seq != null) {
|
||||
seq = new ShopNumberSeq();
|
||||
seq.setNumber(number - 1);
|
||||
seq.setNumber(number-1);
|
||||
seq.setPrefix(seqName);
|
||||
}
|
||||
edit(seq);
|
||||
@ -257,84 +253,88 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl<ShopNumberSeqMappe
|
||||
|
||||
/**
|
||||
* 存的是最大值,取的是范围,如存最大值1,批量是2,则取范围【1+1,1+2】,如果没有则从1开始算即取范围[0+1,0+2]
|
||||
*
|
||||
* @param batchSize
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<Integer> getBatchSpecId(int batchSize) {
|
||||
int start = 0;
|
||||
if (null != redisService.get(RedisKey.STOREDATASPECID)) {
|
||||
start = (Integer) redisService.get(RedisKey.STOREDATASPECID);
|
||||
redisService.set(RedisKey.STOREDATASPECID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
int start=0;
|
||||
if(null!=redisService.get(RedisKey.STOREDATASPECID)){
|
||||
start=(Integer) redisService.get(RedisKey.STOREDATASPECID);
|
||||
redisService.set(RedisKey.STOREDATASPECID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
QueryWrapper<ShopBaseProductSpec> queryWrapper = new QueryWrapper<>();
|
||||
QueryWrapper<ShopBaseProductSpec> queryWrapper= new QueryWrapper<>();
|
||||
queryWrapper.select("max(spec_id) as spec_id");
|
||||
ShopBaseProductSpec shopBaseProductSpec = shopBaseProductSpecService.getOne(queryWrapper);
|
||||
if (null != shopBaseProductSpec) {
|
||||
start = shopBaseProductSpec.getSpec_id();
|
||||
redisService.set(RedisKey.STOREDATASPECID, start + batchSize);
|
||||
ShopBaseProductSpec shopBaseProductSpec=shopBaseProductSpecService.getOne(queryWrapper);
|
||||
if(null!=shopBaseProductSpec){
|
||||
start=shopBaseProductSpec.getSpec_id();
|
||||
redisService.set(RedisKey.STOREDATASPECID,start+batchSize);
|
||||
}
|
||||
if (start == 0) {
|
||||
redisService.set(RedisKey.STOREDATASPECID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
if(start==0){
|
||||
redisService.set(RedisKey.STOREDATASPECID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 存的是最大值,取的是范围,如存最大值1,批量是2,则取范围【1+1,1+2】,如果没有则从1开始算即取范围[0+1,0+2]
|
||||
*
|
||||
* @param batchSize
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<Integer> getBatchSpecItemId(int batchSize) {
|
||||
int start = 0;
|
||||
if (null != redisService.get(RedisKey.STOREDATASPECITEMID)) {
|
||||
start = (Integer) redisService.get(RedisKey.STOREDATASPECITEMID);
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
int start=0;
|
||||
if(null!=redisService.get(RedisKey.STOREDATASPECITEMID)){
|
||||
start=(Integer) redisService.get(RedisKey.STOREDATASPECITEMID);
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
QueryWrapper<ShopProductSpecItem> queryWrapper = new QueryWrapper<>();
|
||||
QueryWrapper<ShopProductSpecItem> queryWrapper= new QueryWrapper<>();
|
||||
queryWrapper.select("max(spec_item_id) as spec_item_id");
|
||||
ShopProductSpecItem shopProductSpecItem = shopProductSpecItemService.getOne(queryWrapper);
|
||||
if (null != shopProductSpecItem) {
|
||||
start = shopProductSpecItem.getSpec_item_id();
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID, start + batchSize);
|
||||
ShopProductSpecItem shopProductSpecItem=shopProductSpecItemService.getOne(queryWrapper);
|
||||
if(null!=shopProductSpecItem){
|
||||
start=shopProductSpecItem.getSpec_item_id();
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize);
|
||||
}
|
||||
if (start == 0) {
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
if(start==0){
|
||||
redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 存的是最大值,取的是范围,如存最大值1,批量是2,则取范围【1+1,1+2】,如果没有则从1开始算即取范围[0+1,0+2]
|
||||
*
|
||||
* @param batchSize
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<Integer> getBatchUserAccountBaseId(int batchSize) {
|
||||
int start = 0;
|
||||
if (null != redisService.get(RedisKey.STOREDATACCOUNTBASEID)) {
|
||||
start = (Integer) redisService.get(RedisKey.STOREDATACCOUNTBASEID);
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
int start=0;
|
||||
if(null!=redisService.get(RedisKey.STOREDATACCOUNTBASEID)){
|
||||
start=(Integer) redisService.get(RedisKey.STOREDATACCOUNTBASEID);
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
Integer maxId = accountService.getAccountMaxId();
|
||||
if (null != maxId) {
|
||||
start = maxId;
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID, start + batchSize);
|
||||
Integer maxId= accountService.getAccountMaxId();
|
||||
if(null!=maxId){
|
||||
start=maxId;
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID,start+batchSize);
|
||||
}
|
||||
if (start == 0) {
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID, start + batchSize);
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
if(start==0){
|
||||
redisService.set(RedisKey.STOREDATACCOUNTBASEID,start+batchSize);
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
return IntStream.rangeClosed(start + 1, start + batchSize).boxed().collect(Collectors.toList());
|
||||
return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.printf(IntStream.rangeClosed(1, 1).boxed().collect(Collectors.toList()).toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ public class ShopOrderReturnController extends BaseControllerImpl {
|
||||
* {"order_id":"DD-20250701-1","reason":"商家协商退款","order_return_vo":{"order_id":"DD-20250701-1","return_items":[{"order_item_id":1,"return_item_num":1,"return_refund_amount":"0.01"}]}}
|
||||
* @return CommonResult 处理结果
|
||||
*/
|
||||
@ApiOperation(value = "商家退款", notes = "商家退款,支持整单或个别商品退货")
|
||||
@ApiOperation(value = "商家退货退款", notes = "商家退货退款,支持整单或个别商品退货")
|
||||
@RequestMapping(value = "/mch/order/doRefund", method = RequestMethod.POST)
|
||||
public CommonResult doRefundForMch(@RequestBody JSONObject params) {
|
||||
return shopOrderReturnService.doRefundForMch(params);
|
||||
|
||||
@ -116,8 +116,7 @@ public class DelayMessageReceiver {
|
||||
// 根据消息分类处理不同类型的消息
|
||||
if (MqConstant.DEAD_EVENT_CATE_ORDER_EXPIRED.equals(category)) {
|
||||
log.info("处理订单超时消息: {}", message);
|
||||
// return handleOrderExpiredMessage(message);
|
||||
return true;
|
||||
return handleOrderExpiredMessage(message);
|
||||
} else if (MqConstant.DEAD_EVENT_CATE_PRE_ORDER.equals(category)) {
|
||||
log.info("处理预订单消息: {}", message);
|
||||
return handlePreOrderMessage(message);
|
||||
|
||||
@ -7,10 +7,9 @@ import com.rabbitmq.client.Channel;
|
||||
import com.suisung.mall.common.api.StateCode;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import com.suisung.mall.common.constant.MqConstant;
|
||||
import com.suisung.mall.common.constant.RedisConstant;
|
||||
import com.suisung.mall.common.modules.order.ShopOrderInfo;
|
||||
import com.suisung.mall.common.utils.DateTimeUtils;
|
||||
import com.suisung.mall.core.web.service.RedisService;
|
||||
import com.suisung.mall.shop.message.service.MqMessageService;
|
||||
import com.suisung.mall.shop.message.service.PushMessageService;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderBaseService;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderInfoService;
|
||||
@ -42,9 +41,6 @@ public class OrderPayedListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OrderPayedListener.class);
|
||||
|
||||
// 最大重试次数
|
||||
private static final int MAX_RETRY_COUNT = 5;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopOrderBaseService shopOrderBaseService;
|
||||
@ -60,7 +56,7 @@ public class OrderPayedListener {
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
private MqMessageService mqMessageService;
|
||||
|
||||
@RabbitHandler
|
||||
public void listener(byte[] data, Channel channel, Message message) throws IOException, InterruptedException {
|
||||
@ -73,72 +69,53 @@ public class OrderPayedListener {
|
||||
public void listener(String data, Channel channel, Message message) throws IOException, InterruptedException {
|
||||
// String messageId = message.getMessageProperties().getMessageId();
|
||||
if (StrUtil.isBlank(data)) {
|
||||
logger.info("[订单支付监听] 收到空订单消息");
|
||||
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
|
||||
logger.info("收到空订单消息");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> order_id_row = Convert.toList(String.class, data);
|
||||
long deliveryTag = message.getMessageProperties().getDeliveryTag();
|
||||
boolean isRedelivered = message.getMessageProperties().isRedelivered();
|
||||
|
||||
String retryCountKey = RedisConstant.Order_Pay_Retry_Count_Key + order_id_row.toString();
|
||||
|
||||
try {
|
||||
logger.info("[订单支付监听] 收到微信异步通知消息. 数据: {}, 订单ID: {}, 是否重投: {}", data, order_id_row, isRedelivered);
|
||||
|
||||
// 检查重试次数
|
||||
int retryCount = getRetryCount(retryCountKey);
|
||||
|
||||
if (retryCount >= MAX_RETRY_COUNT) {
|
||||
logger.error("[订单支付监听] 订单处理已达到最大重试次数: {}, 订单ID: {}, 不再处理该消息", MAX_RETRY_COUNT, order_id_row);
|
||||
channel.basicAck(deliveryTag, false); // 确认消息,避免无限重试
|
||||
redisService.del(retryCountKey); // 清除重试计数
|
||||
return;
|
||||
}
|
||||
|
||||
boolean flag = false;
|
||||
logger.info("收到微信异步通知消息data:{}-chanel:{}-message:{},订单ID:{}", data, channel, message, order_id_row);
|
||||
|
||||
for (String orderId : order_id_row) {
|
||||
//判断是否为线下支付订单
|
||||
ShopOrderInfo orderInfoOld = shopOrderInfoService.get(orderId);
|
||||
if (orderInfoOld == null) {
|
||||
// 记录重试次数
|
||||
incrementRetryCount(retryCountKey);
|
||||
logger.warn("[订单支付监听] 订单在数据库中不存在,增加重试计数. 订单ID: {}, 当前重试次数: {}", orderId, retryCount + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 订单状态
|
||||
int order_state_id = orderInfoOld.getOrder_state_id().intValue();
|
||||
logger.info("[订单支付监听] 当前订单状态: {}, 订单ID: {}", order_state_id, orderId);
|
||||
logger.info("#### 当前订单状态: {} ####", order_state_id);
|
||||
|
||||
// 检查订单是否已经处理过(幂等性检查)
|
||||
if (isOrderPaid(orderInfoOld)) {
|
||||
logger.info("[订单支付监听] 订单已支付,无需重复处理,订单ID: {}", orderId);
|
||||
flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (isOrderPaid(orderInfoOld)) {
|
||||
// logger.info("订单已支付,无需重复处理,订单ID: {}", orderId);
|
||||
// flag = true;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (order_state_id == StateCode.ORDER_STATE_WAIT_PAY) {
|
||||
// 待支付状态
|
||||
logger.info("[订单支付监听] 处理待支付订单. 订单ID: {}", orderId);
|
||||
logger.info("#### 待支付业务分支 ####");
|
||||
flag = shopOrderBaseService.setPaidYes(Collections.singletonList(orderId));
|
||||
} else {
|
||||
//判断是否线下支付
|
||||
if (StateCode.PAYMENT_TYPE_OFFLINE == orderInfoOld.getPayment_type_id().intValue()) {
|
||||
//线下支付,直接处理订单支付状态, 不处理订单状态
|
||||
logger.info("[订单支付监听] 处理线下支付订单. 订单ID: {}", orderId);
|
||||
logger.info("#### 线下业务分支 ####");
|
||||
ShopOrderInfo orderInfo = new ShopOrderInfo();
|
||||
orderInfo.setOrder_id(orderId);
|
||||
orderInfo.setOrder_is_paid(StateCode.ORDER_PAID_STATE_YES);
|
||||
flag = shopOrderInfoService.edit(orderInfo);
|
||||
} else {
|
||||
logger.info("[订单支付监听] 处理其他支付订单. 订单ID: {}", orderId);
|
||||
logger.info("#### 非线下业务分支 ####");
|
||||
flag = shopOrderBaseService.setPaidYes(Collections.singletonList(orderId));
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("[订单支付监听] 支付异步通知回调处理结果: {}, 订单ID: {}", flag, orderId);
|
||||
logger.info("#### 支付异步通知回调处理是否成功:{} ####", flag);
|
||||
// 生成取单号和打印小票
|
||||
if (flag) {
|
||||
// TODO 以下仅处理下单打印的情况,还需要处理退单打印分支。
|
||||
@ -157,16 +134,16 @@ public class OrderPayedListener {
|
||||
// 发送顺丰同城快递
|
||||
Pair<Boolean, String> pairCreateSfOrder = sfExpressApiService.innerCreateSfExpressOrder(orderId, orderPickupNum);
|
||||
if (pairCreateSfOrder == null) {
|
||||
logger.error("[订单支付监听] 顺丰同城下单失败!pairCreateSfOrder 返回空值. 订单ID: {}", orderId);
|
||||
continue;
|
||||
logger.error("顺丰同城下单失败!pairCreateSfOrder 返回空值");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pairCreateSfOrder.getFirst()) {
|
||||
logger.error("[订单支付监听] 顺丰同城下单失败: {}, 订单ID: {}", pairCreateSfOrder.getSecond(), orderId);
|
||||
continue;
|
||||
logger.error("顺丰同城下单失败:{}", pairCreateSfOrder.getSecond());
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("[订单支付监听] 顺丰同城下单成功. 订单ID: {}", orderId);
|
||||
logger.info("顺丰同城下单成功");
|
||||
|
||||
}
|
||||
|
||||
@ -181,16 +158,18 @@ public class OrderPayedListener {
|
||||
payload.put("orderId", orderId);
|
||||
pushMessageService.noticeMerchantEmployeeOrderAction(orderInfoOld.getStore_id(), orderId, title, content, payload);
|
||||
|
||||
// 发送延迟消息 25分钟拣货配送时间(提前5分钟,下单20分钟后,提醒商家及时拣货)
|
||||
Long mchOrderExpireSeconds = shopOrderBaseService.sameCityOrderExpireSeconds(1500L) - 300;
|
||||
redisService.set(RedisConstant.SF_Order_Proc_WillExpire_Key + String.format("%d&%s", orderInfoOld.getStore_id(), orderId), orderId, mchOrderExpireSeconds);
|
||||
|
||||
// 发送延迟消息 25分钟拣货配送时间(下单25分钟后,提醒商家及时拣货)
|
||||
mchOrderExpireSeconds = shopOrderBaseService.sameCityOrderExpireSeconds(1500L);
|
||||
redisService.set(RedisConstant.SF_Order_Proc_Expire_Key + String.format("%d&%s", orderInfoOld.getStore_id(), orderId), orderId, mchOrderExpireSeconds);
|
||||
|
||||
// 发送 预过期 MQ 的推送消息
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("category", MqConstant.DEAD_EVENT_CATE_ORDER_EXPIRED); // 消息分类:1-订单超时消息
|
||||
jsonObject.put("orderId", orderId); // 订单ID
|
||||
jsonObject.put("storeId", orderInfoOld.getStore_id()); // 店铺ID
|
||||
jsonObject.put("title", "您有一笔将超时的订单。"); // 消息标题
|
||||
jsonObject.put("message", String.format("您有一笔将超时的订单:%s,请您及时处理。", orderId)); // 消息内容
|
||||
// 发送延迟消息(提前10分钟)
|
||||
Long mchOrderExpireSeconds = shopOrderBaseService.sameCityOrderExpireSeconds(1500L) - 600;
|
||||
mqMessageService.sendDelayMessage(jsonObject.toString(), mchOrderExpireSeconds * 1000); // 转换为毫秒
|
||||
} catch (Exception e) {
|
||||
log.error("[订单支付监听] 发送推送消息失败. 订单ID: {}", orderId, e);
|
||||
log.error("发送推送消息失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,22 +177,15 @@ public class OrderPayedListener {
|
||||
|
||||
if (flag) {
|
||||
// 操作成功,标记消息消费成功
|
||||
logger.info("[订单支付监听] 消息处理成功,确认消息. 订单ID: {}", order_id_row);
|
||||
channel.basicAck(deliveryTag, false);
|
||||
// 清除重试计数
|
||||
redisService.del(RedisConstant.Order_Pay_Retry_Count_Key + order_id_row);
|
||||
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
|
||||
} else {
|
||||
log.error("[订单支付监听] 消息处理失败,执行setPaidYes异常,当前订单编号:{}", order_id_row);
|
||||
// 增加重试计数
|
||||
incrementRetryCount(retryCountKey);
|
||||
channel.basicReject(deliveryTag, true);
|
||||
log.error("消息消费失败,执行setPaidYes异常,当前订单编号:{}", order_id_row);
|
||||
channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[订单支付监听] 消息处理异常,当前订单编号:{},异常信息:", order_id_row, e);
|
||||
// 增加重试计数
|
||||
incrementRetryCount(retryCountKey);
|
||||
channel.basicReject(deliveryTag, true);
|
||||
log.error("消息消费失败,执行setPaidYes异常,当前订单编号:{},失败原因:", order_id_row, e);
|
||||
channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
@ -225,33 +197,12 @@ public class OrderPayedListener {
|
||||
* @return 是否已支付
|
||||
*/
|
||||
private boolean isOrderPaid(ShopOrderInfo orderInfo) {
|
||||
// ORDER_PAID_STATE_NO = 3010; //未付款
|
||||
// ORDER_PAID_STATE_FINANCE_REVIEW = 3011; //待付款审核
|
||||
// ORDER_PAID_STATE_PART = 3012; //部分付款
|
||||
// ORDER_PAID_STATE_YES = 3013; //已付款
|
||||
// public static final int ORDER_PAID_STATE_NO = 3010; //未付款
|
||||
// public static final int ORDER_PAID_STATE_FINANCE_REVIEW = 3011; //待付款审核
|
||||
// public static final int ORDER_PAID_STATE_PART = 3012; //部分付款
|
||||
// public static final int ORDER_PAID_STATE_YES = 3013; //已付款
|
||||
return orderInfo.getOrder_is_paid() != null &&
|
||||
orderInfo.getOrder_is_paid().intValue() == StateCode.ORDER_PAID_STATE_YES;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取重试次数
|
||||
*
|
||||
* @param retryCountKey 重试计数键
|
||||
* @return 当前重试次数
|
||||
*/
|
||||
private int getRetryCount(String retryCountKey) {
|
||||
Object countObj = redisService.get(retryCountKey);
|
||||
return countObj == null ? 0 : Convert.toInt(countObj, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加重试次数
|
||||
*
|
||||
* @param retryCountKey 重试计数键
|
||||
*/
|
||||
private void incrementRetryCount(String retryCountKey) {
|
||||
int currentCount = getRetryCount(retryCountKey);
|
||||
redisService.set(retryCountKey, currentCount + 1, 3600); // 1小时过期
|
||||
orderInfo.getOrder_is_paid().equals(StateCode.ORDER_PAID_STATE_YES);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.order.listener;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import com.suisung.mall.common.constant.RedisConstant;
|
||||
import com.suisung.mall.shop.message.service.PushMessageService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Slf4j
|
||||
public class RedisKeyExpiredListener implements MessageListener {
|
||||
|
||||
@Resource
|
||||
private PushMessageService pushMessageService;
|
||||
|
||||
/**
|
||||
* Callback for processing received objects through Redis.
|
||||
*
|
||||
* @param message message must not be {@literal null}.
|
||||
* @param pattern pattern matching the channel (if specified) - can be {@literal null}.
|
||||
*/
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
String expiredKey = new String(message.getBody());
|
||||
String patternStr = pattern != null ? new String(pattern) : "无模式";
|
||||
|
||||
// 基本日志记录
|
||||
log.debug("[Redis过期监听] 接收到Redis键过期事件. 过期键: {}, 订阅模式: {}", expiredKey, patternStr);
|
||||
|
||||
// 参数验证
|
||||
if (StrUtil.isBlank(expiredKey)) {
|
||||
log.warn("[Redis过期监听] 接收到空的过期键. 订阅模式: {}", patternStr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (expiredKey.startsWith(RedisConstant.SF_Order_Proc_Expire_Key)) {
|
||||
log.debug("[Redis过期监听] 开始处理订单超时事件. 过期键: {}", expiredKey);
|
||||
|
||||
// storeId&orderId
|
||||
String[] args = expiredKey.replace(RedisConstant.SF_Order_Proc_Expire_Key, "").split("&");
|
||||
if (ArrayUtil.isEmpty(args) || args.length < 2) {
|
||||
log.error("[Redis过期监听] 订单处理超时键格式错误. 键: {} 不符合预期格式", expiredKey);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("[Redis过期监听] 处理订单超时消息. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
boolean result = handleOrderExpiredMessage(args[0], args[1], false);
|
||||
|
||||
if (result) {
|
||||
log.info("[Redis过期监听] 订单超时事件处理成功. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
} else {
|
||||
log.error("[Redis过期监听] 订单超时事件处理失败. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
}
|
||||
} else if (expiredKey.startsWith(RedisConstant.SF_Order_Proc_WillExpire_Key)) {
|
||||
log.debug("[Redis过期监听] 开始处理订单即将(5分钟后)超时事件. 过期键: {}", expiredKey);
|
||||
|
||||
// storeId&orderId
|
||||
String[] args = expiredKey.replace(RedisConstant.SF_Order_Proc_WillExpire_Key, "").split("&");
|
||||
if (ArrayUtil.isEmpty(args) || args.length < 2) {
|
||||
log.error("[Redis过期监听] 订单处理超时键格式错误. 键: {} 不符合预期格式", expiredKey);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("[Redis过期监听] 处理订单即将超时消息. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
boolean result = handleOrderExpiredMessage(args[0], args[1], true);
|
||||
|
||||
if (result) {
|
||||
log.info("[Redis过期监听] 订单即将超时事件处理成功. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
} else {
|
||||
log.error("[Redis过期监听] 订单即将超时事件处理失败. 店铺ID: {}, 订单号: {}", args[0], args[1]);
|
||||
}
|
||||
} else {
|
||||
//log.debug("[Redis过期监听] 忽略非订单超时事件. 过期键: {}", expiredKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理订单超时消息
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param orderId 订单ID
|
||||
* @param willExpire 此刻还是即将
|
||||
* @return 处理结果
|
||||
*/
|
||||
private boolean handleOrderExpiredMessage(String storeId, String orderId, boolean willExpire) {
|
||||
try {
|
||||
String addWord = "";
|
||||
if (willExpire) {
|
||||
addWord = "即将";
|
||||
}
|
||||
|
||||
log.debug("[订单{}超时处理] 开始处理订单超时消息. 店铺ID: {}, 订单号: {}", addWord, storeId, orderId);
|
||||
|
||||
// 参数验证
|
||||
if (StrUtil.isBlank(orderId) && StrUtil.isBlank(storeId)) {
|
||||
log.warn("[订单{}超时处理] 订单ID和店铺ID不能同时为空. 店铺ID: {}, 订单号: {}", addWord, storeId, orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("[订单{}超时处理] 订单号为空. 店铺ID: {}", addWord, storeId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(storeId)) {
|
||||
log.warn("[订单{}超时处理] 店铺ID为空. 订单号: {}", addWord, orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
String title = "有一笔" + addWord + "超时的订单!";
|
||||
String content = "您有一笔" + addWord + "超时的订单[" + orderId + "],请及时处理。";
|
||||
log.debug("[订单{}超时处理] 准备推送消息. 标题: {}, 内容: {}", addWord, title, content);
|
||||
|
||||
// 构造推送消息内容
|
||||
JSONObject payload = new JSONObject();
|
||||
if (willExpire) {
|
||||
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ONLINE_ORDER_LIST);
|
||||
} else {
|
||||
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ABNORMAL_ORDER_LIST);
|
||||
}
|
||||
payload.put("orderId", orderId);
|
||||
log.debug("[订单{}超时处理] 推送消息载荷已准备: {}", addWord, payload);
|
||||
|
||||
// 发送推送消息给商家员工
|
||||
log.debug("[订单{}超时处理] 发送推送消息给商家员工. 店铺ID: {}, 订单号: {}", addWord, storeId, orderId);
|
||||
pushMessageService.noticeMerchantEmployeeOrderAction(
|
||||
Convert.toInt(storeId), orderId, title,
|
||||
content, payload);
|
||||
|
||||
log.info("[订单{}超时处理] 订单超时消息处理完成. 订单号: {}, 店铺ID: {}, 推送类别: {}",
|
||||
addWord, orderId, storeId, CommonConstant.PUSH_MSG_CATE_MCH_ABNORMAL_ORDER_LIST);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("[订单超时处理] 处理订单超时消息时发生异常. 订单号: {}, 店铺ID: {}", orderId, storeId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,20 +36,10 @@ public interface ShopOrderLklService extends IBaseService<ShopOrderLkl> {
|
||||
* 根据拉卡拉的回调数据,更新拉卡拉的订单信息
|
||||
*
|
||||
* @param lklPayNotifyDataJson 异步通知返回的body json数据:
|
||||
* // 非合单返回的数据异步通知返回的 body json数据:{"out_trade_no":"202203151637334864280014","trade_no":"2022031566210203291925","log_no":"66210203291925",
|
||||
* // {"out_trade_no":"202203151637334864280014","trade_no":"2022031566210203291925","log_no":"66210203291925",
|
||||
* // "acc_trade_no":"2022031522001483661454130929 ","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"1",
|
||||
* // "payer_amount":"1","acc_settle_amount":"1","trade_time":"20220315163808","user_id1":"app***@163.com",
|
||||
* // "user_id2":"2088432881453660","notify_url":"https://www.baidu.com","account_type":"ALIPAY","card_type":"99"}
|
||||
* <p>
|
||||
* // 合单返回的数据异步通知返回的 body json数据:{"out_trade_no":"DD-20250830-10","trade_no":"20250830110113130266250034160499","log_no":"66250034160499",
|
||||
* // "acc_trade_no":"4200002826202508306761393882","trade_status":"SUCCESS","trade_state":"SUCCESS","total_amount":"2","payer_amount":"2","acc_settle_amount":"2",
|
||||
* // "acc_mdiscount_amount":"0","acc_discount_amount":"0","trade_time":"20250830180435","user_id1":"oDVKR7T0qxg6O8tqIL9SgY6LXqqQ",
|
||||
* // "user_id2":"oVxsc1QRAqDRv_gAmXuLZwSVSL18","notify_url":"https://mall.gpxscs.cn/mobile/pay/index/lkl_wxPay_notify_url","account_type":"WECHAT",
|
||||
* // "bank_type":"OTHERS","card_type":"02","merchant_no":"8226330541100GU","remark":"","sub_mch_id":"803819329",
|
||||
* // "out_split_rsp_infos":[{"sub_trade_no":"20250830110113130266250034112794","sub_log_no":"66250034112794","out_sub_trade_no":"ORD_DD-20250830-10",
|
||||
* // "merchant_no":"8226330541100GU","term_no":"N5817779","amount":"1","settle_type":"0"},{"sub_trade_no":"20250830110113130266250034160498","sub_log_no":"66250034160498",
|
||||
* // "out_sub_trade_no":"DF_DD-20250830-10","merchant_no":"822584059990FYP","term_no":"N5811590","amount":"1","settle_type":"0"}],"trade_req_date":"20250830","gb_amount":"",
|
||||
* // "qb_amount":""}
|
||||
* @return
|
||||
*/
|
||||
Boolean addOrUpdateByLklPayNotifyDataJson(JSONObject lklPayNotifyDataJson);
|
||||
@ -63,54 +53,4 @@ public interface ShopOrderLklService extends IBaseService<ShopOrderLkl> {
|
||||
* @return
|
||||
*/
|
||||
List<ShopOrderLkl> selectByOrderId(String orderId, String lklLogNo, String storeId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据店铺Id、订单编号查询一条记录
|
||||
*
|
||||
* @param storeId
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
ShopOrderLkl getByStoreIdAndOrderId(Integer storeId, String orderId);
|
||||
|
||||
/**
|
||||
* 根据商户号、交易流水号、对账单流水号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo
|
||||
* @param lklTradeNo
|
||||
* @param lklSubLogNo
|
||||
* @return
|
||||
*/
|
||||
ShopOrderLkl getByLklMchNoAndSubTradeNoAndSubLogNo(String lklMerchantNo, String lklTradeNo, String lklSubLogNo);
|
||||
|
||||
|
||||
/**
|
||||
* 根据商户号、确认收货交易流水号、确认收货对账单流水号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param lklReceiveTradeNo 拉卡拉确认收货交易流水号
|
||||
* @param lklReceiveLogNo 拉卡拉确认收货对账单流水号
|
||||
* @return ShopOrderLkl 拉卡拉订单记录
|
||||
*/
|
||||
ShopOrderLkl getByLklMchNoAndReceiveTradeNoAndReceiveLogNo(String lklMerchantNo, String lklReceiveTradeNo, String lklReceiveLogNo);
|
||||
|
||||
/**
|
||||
* 根据商户号、确认收货交易流水号、确认收货对账单流水号更新确认收货状态
|
||||
*
|
||||
* @param lklReceiveLogNo 拉卡拉确认收货对账单流水号
|
||||
* @param separateStatus 分账状态:1-已分账;2-未分账;3-分账已失败;
|
||||
* @param separateRemark 分账问题备注;
|
||||
* @return
|
||||
*/
|
||||
Boolean updateSeparateStatusByReceiveLogNo(String lklReceiveLogNo, Integer separateStatus, String separateRemark);
|
||||
|
||||
|
||||
/**
|
||||
* 不抛异常更新
|
||||
*
|
||||
* @param record
|
||||
* @return
|
||||
*/
|
||||
Boolean safeUpdate(ShopOrderLkl record);
|
||||
}
|
||||
|
||||
@ -175,17 +175,6 @@ public interface ShopOrderReturnService extends IBaseService<ShopOrderReturn> {
|
||||
*/
|
||||
CommonResult addWholeItems(String orderId, Boolean isSystemOpt, String remark);
|
||||
|
||||
/**
|
||||
* 对已存在部分退款的订单,进行剩余商品的全部退款
|
||||
* 该方法用于处理订单中部分商品已经申请退款后,对剩余商品进行整单退款的场景
|
||||
*
|
||||
* @param orderId 订单ID
|
||||
* @param isSystemOpt 是否系统自动操作
|
||||
* @param remark 退单备注
|
||||
* @return CommonResult 退款申请结果
|
||||
*/
|
||||
CommonResult addRemainingItems(String orderId, Boolean isSystemOpt, String remark);
|
||||
|
||||
/**
|
||||
* 退货单转单-供应商
|
||||
*
|
||||
|
||||
@ -331,10 +331,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
@Autowired
|
||||
private ShopDistributionPlantformUserService shopDistributionPlantformUserService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopOrderLklService shopOrderLklService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
@ -589,7 +585,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(order_key)) {
|
||||
if (order_key.startsWith("DD_") || order_key.startsWith("DD-")) {
|
||||
if (order_key.startsWith("DD-")) {
|
||||
params.put("order_id:eq", order_key);
|
||||
} else {
|
||||
params.put("order_title:like", order_key);
|
||||
@ -632,61 +628,43 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* 订单详情
|
||||
*
|
||||
* @param order_id 订单ID
|
||||
* @return 订单详情数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map detail(String order_id) {
|
||||
log.debug("开始获取订单详情,订单ID: {}", order_id);
|
||||
|
||||
Map data = new HashMap();
|
||||
List<String> order_ids = Convert.toList(String.class, order_id);
|
||||
if (CollUtil.isEmpty(order_ids)) {
|
||||
log.warn("订单ID列表为空");
|
||||
return data;
|
||||
}
|
||||
|
||||
// 获取订单信息
|
||||
Map row = Convert.toMap(String.class, Object.class, get(order_ids.get(0)));
|
||||
if (CollUtil.isEmpty(row)) {
|
||||
log.warn("订单信息不存在,订单ID: {}", order_ids.get(0));
|
||||
throw new ApiException(I18nUtil._("订单不存在!"));
|
||||
}
|
||||
|
||||
//买家订单或者 // todo 分销订单
|
||||
UserDto user = getCurrentUser();
|
||||
if (user == null) {
|
||||
log.warn("用户信息异常");
|
||||
throw new ApiUserException(I18nUtil._("用户信息异常!"));
|
||||
}
|
||||
Integer user_id = user.getId();
|
||||
log.debug("当前用户ID: {}", user_id);
|
||||
|
||||
QueryWrapper<ShopDistributionUserOrder> userOrderQueryWrapper = new QueryWrapper<>();
|
||||
userOrderQueryWrapper.eq("user_id", user_id).in("order_id", order_ids);
|
||||
ShopDistributionUserOrder distributionUserOrder = shopDistributionUserOrderService.findOne(userOrderQueryWrapper);
|
||||
Map distributionUserOrderMap = Convert.toMap(String.class, Object.class, distributionUserOrder);
|
||||
|
||||
// 检查用户是否有权限访问该订单(作为买家或分销商)
|
||||
boolean hasBuyerRights = CheckUtil.checkDataRights(user_id, row, "buyer_user_id");
|
||||
boolean hasDistributionRights = CheckUtil.checkDataRights(user_id, distributionUserOrderMap, "user_id");
|
||||
log.debug("订单访问权限检查,买家权限: {}, 分销权限: {}", hasBuyerRights, hasDistributionRights);
|
||||
|
||||
if (hasBuyerRights || hasDistributionRights) {
|
||||
if (CheckUtil.checkDataRights(user_id, row, "buyer_user_id") || CheckUtil.checkDataRights(user_id, distributionUserOrderMap, "user_id")) {
|
||||
data = getOrderDetail(order_id, row);
|
||||
log.debug("获取订单详细信息完成");
|
||||
|
||||
// diy, 判断是否上传素材
|
||||
//diy, 判断是否上传素材
|
||||
List<Map> items = (List<Map>) data.get("items");
|
||||
if (CollUtil.isNotEmpty(items)) {
|
||||
for (Map item : items) {
|
||||
String design_file_images = Convert.toStr(item.get("design_file_images"));
|
||||
if (StrUtil.isNotBlank(design_file_images)) {
|
||||
// row = apply_filters("product-cart-add", row);
|
||||
log.debug("订单项包含设计文件图片");
|
||||
}
|
||||
for (Map item : items) {
|
||||
String design_file_images = Convert.toStr(item.get("design_file_images"));
|
||||
if (StrUtil.isNotBlank(design_file_images)) {
|
||||
// row = apply_filters("product-cart-add", row);
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,19 +675,15 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
Integer delivery_istimer = Convert.toInt(data.get("delivery_istimer"));
|
||||
String deliveryTime = getDeliveryTime(delivery_time, delivery_time_rang, delivery_time_h, delivery_time_i, delivery_istimer);
|
||||
data.put("delivery_time_name", deliveryTime);
|
||||
log.debug("配送时间计算完成: {}", deliveryTime);
|
||||
|
||||
// 判断活动信息
|
||||
Integer activity_type_id = Convert.toInt(data.get("activity_type_id"));
|
||||
if (ObjectUtil.equal(StateCode.ACTIVITY_TYPE_GROUPBOOKING, activity_type_id)) {
|
||||
log.debug("处理拼团活动订单");
|
||||
QueryWrapper<ShopActivityGroupbookingHistory> historyQueryWrapper = new QueryWrapper<>();
|
||||
historyQueryWrapper.eq("user_id", user_id).in("order_id", order_ids);
|
||||
ShopActivityGroupbookingHistory group_booking_row = groupbookingHistoryService.findOne(historyQueryWrapper);
|
||||
if (group_booking_row != null) {
|
||||
data.put("gb_id", group_booking_row.getGb_id());
|
||||
log.debug("获取拼团ID: {}", group_booking_row.getGb_id());
|
||||
}
|
||||
|
||||
data.put("gb_id", group_booking_row.getGb_id());
|
||||
}
|
||||
|
||||
Map queryParams = new HashMap();
|
||||
@ -719,7 +693,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
|
||||
Map result = payService.findConsumeRecordHandleName(queryParams);
|
||||
data.putAll(result);
|
||||
log.debug("支付记录处理完成");
|
||||
|
||||
// 订单倒计时
|
||||
boolean show_cancel_time = accountBaseConfigService.getConfig("show_cancel_time", false);
|
||||
@ -736,7 +709,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
order_time = DateUtil.offsetSecond(order_time, (int) (order_autocancel_time * 60 * 60));
|
||||
long remain_pay_time = (order_time.getTime() - new DateTime().getTime()) / 1000;
|
||||
data.put("remain_pay_time", remain_pay_time); // 修复以分钟扫描清除订单导致的误差
|
||||
log.debug("订单自动取消倒计时计算完成,剩余时间: {}秒", remain_pay_time);
|
||||
}
|
||||
|
||||
//自动收货倒计时 order_autofinish_time
|
||||
@ -747,15 +719,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
long remain_autofinish_time = (order_deal_time.getTime() - new DateTime().getTime()) / 1000;
|
||||
|
||||
data.put("remain_autofinish_time", remain_autofinish_time); // 修复以分钟扫描清除订单导致的误差
|
||||
log.debug("订单自动收货倒计时计算完成,剩余时间: {}秒", remain_autofinish_time);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.warn("用户无权限访问该订单,用户ID: {}, 订单ID: {}", user_id, order_id);
|
||||
throw new ApiException(I18nUtil._("无该订单访问权限!"));
|
||||
}
|
||||
|
||||
log.info("订单详情获取完成,订单ID: {}", order_id);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -788,14 +755,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
if (CollUtil.isNotEmpty(order_info)) base_row.putAll(order_info);
|
||||
if (CollUtil.isNotEmpty(order_data)) base_row.putAll(order_data);
|
||||
|
||||
// update 2025-09-10 增加KLK支付信息
|
||||
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByStoreIdAndOrderId(shopOrderInfo.getStore_id(), order_id);
|
||||
if (shopOrderLkl != null) {
|
||||
base_row.put("lkl_merchant_no", shopOrderLkl.getLkl_merchant_no());
|
||||
base_row.put("lkl_trade_no", shopOrderLkl.getWx_transaction_id());
|
||||
base_row.put("lkl_log_no", shopOrderLkl.getLkl_sub_log_no());
|
||||
}
|
||||
|
||||
// 是否为虚拟商品
|
||||
ShopOrderChainCode shopOrderChainCode = orderChainCodeService.get(order_id);
|
||||
Map order_chain_code = Convert.toMap(String.class, Object.class, shopOrderChainCode);
|
||||
@ -2375,10 +2334,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
queryWrapper.eq("order_state_id", order_state_id).in("order_is_shipped", Arrays.asList(StateCode.ORDER_SHIPPED_STATE_NO, StateCode.ORDER_SHIPPED_STATE_PART)).eq("order_is_received", 0);
|
||||
break;
|
||||
case StateCode.ORDER_STATE_SHIPPED: // 待收获确认
|
||||
shopOrderInfo.setOrder_is_received(CommonConstant.Enable);
|
||||
shopOrderInfo.setOrder_is_received(1);
|
||||
shopOrderInfo.setOrder_settlement_time(time);
|
||||
shopOrderInfo.setOrder_qs_time(time);
|
||||
queryWrapper.eq("order_state_id", order_state_id).eq("order_is_received", CommonConstant.Disable);
|
||||
queryWrapper.eq("order_state_id", order_state_id).eq("order_is_received", 0);
|
||||
break;
|
||||
default:
|
||||
shopOrderInfo.setOrder_settlement_time(time);
|
||||
@ -3287,8 +3246,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
|
||||
Integer order_item_inventory_lock = order_item_row.getOrder_item_inventory_lock();
|
||||
String item_src_id = order_item_row.getItem_src_id();
|
||||
|
||||
logger.debug("尝试执行订单商品item_src_id:{} 锁定库存:{}", item_src_id, order_item_inventory_lock);
|
||||
if (ObjectUtil.equal(1002, order_item_inventory_lock) && CheckUtil.isNotEmpty(item_src_id)) {
|
||||
Long item_id = order_item_row.getItem_id();
|
||||
if (shopProductItemService.lockSkuStock(item_id, order_item_row.getOrder_item_quantity()) <= 0) {
|
||||
@ -3296,11 +3253,9 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
throw new ApiException(String.format(I18nUtil._("更改: %s 冻结库存失败!"), item_id));
|
||||
}
|
||||
|
||||
logger.debug("成功执行订单商品item_src_id:{} 锁定库存:{}", item_src_id, order_item_inventory_lock);
|
||||
|
||||
// RMK 第三方数据同步相关:redis 给这个商品减去对应的库存
|
||||
Map<String, Integer> stockDeltaMap = new HashMap<>();
|
||||
stockDeltaMap.put(item_src_id, -order_item_quantity);
|
||||
stockDeltaMap.put(Convert.toStr(item_src_id), -order_item_quantity);
|
||||
syncThirdDataService.incrProductStockToRedis(stockDeltaMap);
|
||||
}
|
||||
}
|
||||
@ -4850,7 +4805,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
// 用户权限判断
|
||||
// 权限判断
|
||||
UserDto user = getCurrentUser();
|
||||
if (user == null) {
|
||||
throw new ApiUserException(I18nUtil._("用户信息异常!"));
|
||||
@ -4947,145 +4902,87 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认收货处理
|
||||
* 订单确认收货
|
||||
*
|
||||
* @param order_ids 订单ID列表
|
||||
* @param order_rows 订单数据列表
|
||||
* @return 是否处理成功
|
||||
* @param order_ids 订单id
|
||||
* @param order_rows 订单数据
|
||||
*/
|
||||
@Override
|
||||
public boolean receive(List<String> order_ids, List<ShopOrderBase> order_rows) {
|
||||
// 检测数据是否合法,过滤允许修改的数据
|
||||
if (CollUtil.isEmpty(order_ids)) {
|
||||
log.warn("[确认收货] 参数校验失败:订单ID列表为空");
|
||||
throw new ApiException(I18nUtil._("请选择需要确认收货的订单!"));
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(order_rows)) {
|
||||
log.debug("[确认收货] 订单数据列表为空,根据订单ID列表查询订单数据");
|
||||
order_rows = gets(order_ids);
|
||||
}
|
||||
|
||||
// 检查订单数据是否存在
|
||||
if (CollUtil.isEmpty(order_rows)) {
|
||||
log.warn("[确认收货] 无法获取订单数据: orderIds={}", order_ids);
|
||||
throw new ApiException(I18nUtil._("无法获取订单数据!"));
|
||||
}
|
||||
|
||||
List<String> receive_id_row = new ArrayList<>();
|
||||
List<String> not_eligible_orders = new ArrayList<>(); // 记录不符合条件的订单
|
||||
|
||||
// 遍历订单列表,处理满足收货条件的订单
|
||||
for (ShopOrderBase order_row : order_rows) {
|
||||
// 判断订单是否可以确认收货
|
||||
// 是否允许确认收货?
|
||||
if (ifReceive(order_row.getOrder_state_id())) {
|
||||
receive_id_row.add(order_row.getOrder_id());
|
||||
log.info("[确认收货] 处理订单: orderId={}, currentState={}", order_row.getOrder_id(), order_row.getOrder_state_id());
|
||||
} else {
|
||||
not_eligible_orders.add(order_row.getOrder_id());
|
||||
log.warn("[确认收货] 订单状态不满足收货条件: orderId={}, currentState={}", order_row.getOrder_id(), order_row.getOrder_state_id());
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有符合条件的订单
|
||||
if (CollUtil.isEmpty(receive_id_row)) {
|
||||
log.warn("[确认收货] 无符合确认收货条件的订单,总订单数={},不符合条件订单数={}", order_rows.size(), not_eligible_orders.size());
|
||||
// 记录所有订单的详细状态信息
|
||||
for (ShopOrderBase order_row : order_rows) {
|
||||
log.warn("[确认收货] 订单状态详情: orderId={}, currentState={}", order_row.getOrder_id(), order_row.getOrder_state_id());
|
||||
}
|
||||
// 增加积分和经验
|
||||
// todo 目前付款支付积分,此处为收货后发放
|
||||
Integer user_id = order_row.getBuyer_user_id();
|
||||
String order_id = order_row.getOrder_id();
|
||||
Integer store_id = order_row.getStore_id();
|
||||
|
||||
// 如果是通过顺丰通知触发的收货,且订单已经是完成状态,则直接返回成功
|
||||
if (order_rows.size() == 1 && not_eligible_orders.size() == 1) {
|
||||
ShopOrderBase order = order_rows.get(0);
|
||||
// 如果订单已经是完成状态,则认为收货成功
|
||||
if (ObjectUtil.equal(order.getOrder_state_id(), StateCode.ORDER_STATE_FINISH)) {
|
||||
log.info("[确认收货] 订单已经是完成状态,直接返回成功: orderId={}", order.getOrder_id());
|
||||
return true;
|
||||
ShopOrderData order_data_row = shopOrderDataService.get(order_id);
|
||||
BigDecimal order_points_add = order_data_row.getOrder_points_add();
|
||||
|
||||
BigDecimal order_points_add_all = order_points_add.add(order_data_row.getOrder_double_points_add());
|
||||
|
||||
if (CheckUtil.isNotEmpty(order_points_add_all)) {
|
||||
String desc = String.format(I18nUtil._("购物获取积分 %s,订单号 %s"), order_points_add_all, order_id);
|
||||
if (!payService.points(user_id, order_points_add_all, PointsType.POINTS_TYPE_CONSUME, desc, store_id, null, order_id)) {
|
||||
throw new ApiException(I18nUtil._("积分操作失败!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// throw new ApiException(I18nUtil._("无符合确认收货条件的订单!"));
|
||||
log.info("[确认收货] 无符合确认收货条件的订单!");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("[确认收货] 符合条件的订单数量: eligibleCount={}, totalChecked={}", receive_id_row.size(), order_rows.size());
|
||||
|
||||
// 处理符合条件的订单
|
||||
for (ShopOrderBase order_row : order_rows) {
|
||||
// 只处理符合条件的订单
|
||||
if (!receive_id_row.contains(order_row.getOrder_id())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 增加积分和经验
|
||||
// todo 目前付款支付积分,此处为收货后发放
|
||||
Integer user_id = order_row.getBuyer_user_id();
|
||||
String order_id = order_row.getOrder_id();
|
||||
Integer store_id = order_row.getStore_id();
|
||||
|
||||
ShopOrderData order_data_row = shopOrderDataService.get(order_id);
|
||||
if (order_data_row == null) {
|
||||
log.warn("[确认收货] 无法获取订单数据: orderId={}", order_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
BigDecimal order_points_add = order_data_row.getOrder_points_add();
|
||||
BigDecimal order_double_points_add = order_data_row.getOrder_double_points_add();
|
||||
BigDecimal order_points_add_all = order_points_add != null ? order_points_add : BigDecimal.ZERO;
|
||||
order_points_add_all = order_points_add_all.add(order_double_points_add != null ? order_double_points_add : BigDecimal.ZERO);
|
||||
|
||||
// 发放购物积分
|
||||
if (CheckUtil.isNotEmpty(order_points_add_all) && order_points_add_all.compareTo(BigDecimal.ZERO) > 0) {
|
||||
String desc = String.format(I18nUtil._("购物获取积分 %s,订单号 %s"), order_points_add_all, order_id);
|
||||
log.debug("[确认收货] 发放购物积分: userId={}, points={}, desc={}", user_id, order_points_add_all, desc);
|
||||
if (!payService.points(user_id, order_points_add_all, PointsType.POINTS_TYPE_CONSUME, desc, store_id, null, order_id)) {
|
||||
log.error("[确认收货] 积分操作失败: userId={}, points={}, orderId={}", user_id, order_points_add_all, order_id);
|
||||
// throw new ApiException(I18nUtil._("积分操作失败!"));
|
||||
// todo 根据送花郎插件是否开启显示是否需要分钱给不同商户
|
||||
/*
|
||||
boolean hall_enable = accountBaseConfigService.getConfig("hall_enable", false);
|
||||
if (hall_enable) {
|
||||
BigDecimal order_commission_fee = order_data_row.getOrder_commission_fee();
|
||||
sendMoneyForTransfer(order_row, order_commission_fee);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// todo 根据送花郎插件是否开启显示是否需要分钱给不同商户
|
||||
/*
|
||||
boolean hall_enable = accountBaseConfigService.getConfig("hall_enable", false);
|
||||
if (hall_enable) {
|
||||
BigDecimal order_commission_fee = order_data_row.getOrder_commission_fee();
|
||||
sendMoneyForTransfer(order_row, order_commission_fee);
|
||||
}
|
||||
*/
|
||||
// todo 目前付款成功发放佣金,此处为收货后发放
|
||||
// 分销功能。
|
||||
String fx_settle_type = accountBaseConfigService.getConfig("fx_settle_type", "receive");
|
||||
if (StrUtil.equals(fx_settle_type, "receive")) {
|
||||
// todo settleDistributionUserOrder
|
||||
shopDistributionUserOrderService.settleDistributionUserOrder(order_id);
|
||||
}
|
||||
|
||||
// todo 目前付款成功发放佣金,此处为收货后发放
|
||||
// 分销功能。
|
||||
String fx_settle_type = accountBaseConfigService.getConfig("fx_settle_type", "receive");
|
||||
if (StrUtil.equals(fx_settle_type, "receive")) {
|
||||
log.debug("[确认收货] 处理分销订单: orderId={}", order_id);
|
||||
// todo settleDistributionUserOrder
|
||||
shopDistributionUserOrderService.settleDistributionUserOrder(order_id);
|
||||
}
|
||||
// 重要;拉卡拉给平台和代理商分账
|
||||
Pair<Boolean, String> retOrderSeparateRet = lakalaApiService.innerDoOrderSeparate(order_row.getOrder_id(), Convert.toStr(order_row.getStore_id()));
|
||||
if (!retOrderSeparateRet.getFirst()) {
|
||||
throw new ApiException(I18nUtil._("平台或代理商分账失败: " + retOrderSeparateRet.getSecond()));
|
||||
}
|
||||
|
||||
// 统计总营业额
|
||||
ShopStoreAnalytics analytics_row = shopStoreAnalyticsService.get(store_id);
|
||||
if (analytics_row != null) {
|
||||
// 统计总营业额
|
||||
ShopStoreAnalytics analytics_row = shopStoreAnalyticsService.get(store_id);
|
||||
BigDecimal order_payment_amount = order_row.getOrder_payment_amount();
|
||||
log.debug("[确认收货] 更新店铺营业额: storeId={}, amount={}", store_id, order_payment_amount);
|
||||
analytics_row.setStore_trade_amount(NumberUtil.add(analytics_row.getStore_trade_amount(), order_payment_amount != null ? order_payment_amount : BigDecimal.ZERO));
|
||||
analytics_row.setStore_trade_amount(NumberUtil.add(analytics_row.getStore_trade_amount(), order_payment_amount));
|
||||
if (!shopStoreAnalyticsService.edit(analytics_row)) {
|
||||
log.error("[确认收货] 更新店铺营业额失败: storeId={}", store_id);
|
||||
// throw new ApiException(ResultCode.FAILED);
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
} else {
|
||||
log.warn("[确认收货] 无法获取店铺统计信息: storeId={}", store_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(receive_id_row)) {
|
||||
throw new ApiException(I18nUtil._("无符合确认收货条件的订单!"));
|
||||
}
|
||||
|
||||
// 修改订单状态, 随机去一个订单获取店铺编号
|
||||
ShopOrderBase shopOrderBase = order_rows.stream()
|
||||
.filter(order -> receive_id_row.contains(order.getOrder_id()))
|
||||
.findFirst()
|
||||
.orElse(order_rows.get(0));
|
||||
ShopOrderBase shopOrderBase = order_rows.get(0);
|
||||
Integer store_id = shopOrderBase.getStore_id();
|
||||
log.debug("[确认收货] 修改订单状态: storeId={}", store_id);
|
||||
editNextState(receive_id_row, store_id, StateCode.ORDER_STATE_SHIPPED, order_rows, 0);
|
||||
|
||||
// 如果是商家,且启用供应商,则商家看到供应商店铺商品 store_type = 2
|
||||
@ -5093,9 +4990,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
UserDto user = getCurrentUser();
|
||||
store_id = user != null ? Convert.toInt(user.getStore_id(), 0) : 0;
|
||||
|
||||
// 处理供应商市场的库存增加逻辑
|
||||
if (ifSupplierMarket && CheckUtil.isNotEmpty(store_id)) {
|
||||
log.debug("[确认收货] 处理供应商市场库存: storeId={}", store_id);
|
||||
// 供应商商品,增加商家库存
|
||||
QueryWrapper<ShopOrderItem> itemQueryWrapper = new QueryWrapper<>();
|
||||
itemQueryWrapper.in("order_id", receive_id_row);
|
||||
@ -5107,39 +5002,30 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
productItemQueryWrapper.in("item_src_id", item_src_ids).eq("store_id", store_id);
|
||||
List<ShopProductItem> product_item_rows = shopProductItemService.find(productItemQueryWrapper);
|
||||
|
||||
// 更新供应商商品库存
|
||||
log.debug("[确认收货] 更新供应商商品库存: itemsCount={}", product_item_rows.size());
|
||||
for (ShopProductItem product_item_row : product_item_rows) {
|
||||
String item_src_id = product_item_row.getItem_src_id();
|
||||
Optional<ShopOrderItem> orderItemOpl = order_item_rows.stream().filter(s -> ObjectUtil.equal(s.getItem_id(), item_src_id)).findFirst();
|
||||
if (orderItemOpl.isPresent()) {
|
||||
ShopOrderItem shopOrderItem = orderItemOpl.get();
|
||||
Integer order_item_quantity = shopOrderItem.getOrder_item_quantity();
|
||||
if (order_item_quantity != null && order_item_quantity > 0) {
|
||||
log.debug("[确认收货] 更新商品库存: itemId={}, oldQuantity={}, addQuantity={}",
|
||||
item_src_id, product_item_row.getItem_quantity(), order_item_quantity);
|
||||
product_item_row.setItem_quantity(product_item_row.getItem_quantity() + order_item_quantity);
|
||||
if (!shopProductItemService.edit(product_item_row)) {
|
||||
log.error("[确认收货] 更新商品库存失败: itemId={}", item_src_id);
|
||||
// throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
product_item_row.setItem_quantity(product_item_row.getItem_quantity() + order_item_quantity);
|
||||
if (!shopProductItemService.edit(product_item_row)) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("[确认收货] 处理完成: processedOrders={}", receive_id_row.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单确认收货(定时任务用途)
|
||||
*
|
||||
* @param order_id 订单id
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean receive(String order_id, ShopOrderBase orderBase) {
|
||||
return receive(Collections.singletonList(order_id), null);
|
||||
}
|
||||
@ -7961,13 +7847,12 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
/**
|
||||
* 是否可以确认收货
|
||||
*
|
||||
* @param orderStateId 订单状态
|
||||
* @return boolean true-可确认收货,false-不可确认收货
|
||||
* @param order_state_id 订单状态
|
||||
* @return boolean true-可,false-不可
|
||||
* @access public
|
||||
*/
|
||||
private boolean ifReceive(Integer orderStateId) {
|
||||
// 只有已发货已签收状态的订单才能确认收货
|
||||
return ObjectUtil.equal(orderStateId, StateCode.ORDER_STATE_SHIPPED) ||
|
||||
ObjectUtil.equal(orderStateId, StateCode.ORDER_STATE_RECEIVED);
|
||||
private boolean ifReceive(Integer order_state_id) {
|
||||
return ObjectUtil.equal(order_state_id, StateCode.ORDER_STATE_SHIPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8120,14 +8005,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
order_info_row.putAll(order_data_row);
|
||||
order_info_row.put("item", order_item_temp_rows.get(order_id));
|
||||
|
||||
// update 2025-09-10 增加KLK支付信息
|
||||
ShopOrderLkl shopOrderLkl = shopOrderLklService.getByStoreIdAndOrderId(store_id, order_id);
|
||||
if (shopOrderLkl != null) {
|
||||
order_info_row.put("lkl_merchant_no", shopOrderLkl.getLkl_merchant_no());
|
||||
order_info_row.put("lkl_trade_no", shopOrderLkl.getWx_transaction_id());
|
||||
order_info_row.put("lkl_log_no", shopOrderLkl.getLkl_sub_log_no());
|
||||
}
|
||||
|
||||
Optional<Map> store_row_Opl = store_rows.stream().filter(s -> ObjectUtil.equal(store_id, Convert.toInt(s.get("store_id")))).findFirst();
|
||||
Map store_row = store_row_Opl.orElseGet(HashMap::new);
|
||||
order_info_row.put("self_support", store_row.get("store_is_selfsupport"));
|
||||
@ -8636,14 +8513,12 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
* 2、商家的详细地址、电话和经纬度
|
||||
* 3、收货人的姓名、电话、详细地址、经纬度
|
||||
*
|
||||
* @param devId 开发者ID
|
||||
* @param shopOrderId 商城订单id
|
||||
* @param orderPickupNum 订单取货编号
|
||||
* @return SFCreateOrderReq 顺丰同城订单请求对象,如果构建失败返回null
|
||||
* @param shopOrderId 商城订单id
|
||||
* @return
|
||||
*/
|
||||
public SFCreateOrderReq buildSFOrderData(Integer devId, String shopOrderId, Long orderPickupNum) {
|
||||
if (StrUtil.isBlank(shopOrderId)) {
|
||||
logger.error("构建顺丰订单失败:缺少订单Id,devId={}, shopOrderId={}", devId, shopOrderId);
|
||||
logger.error("缺少订单Id");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -8653,13 +8528,13 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
queryWrapper.eq("order_id", shopOrderId);
|
||||
List<ShopOrderItem> shopOrderItemList = shopOrderItemService.list(queryWrapper);
|
||||
if (shopOrderBase == null || shopOrderData == null || CollUtil.isEmpty(shopOrderItemList)) {
|
||||
logger.error("构建顺丰订单失败:无法获取订单信息,订单ID={}", shopOrderId);
|
||||
logger.error("无法获取订单信息!");
|
||||
return null;
|
||||
}
|
||||
|
||||
Integer storeId = shopOrderBase.getStore_id();
|
||||
if (storeId == null || storeId <= 0) {
|
||||
logger.error("构建顺丰订单失败:缺少店铺Id,订单ID={},storeId={}", shopOrderId, storeId);
|
||||
logger.error("缺少店铺 Id!");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -8668,7 +8543,12 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
ShopOrderDeliveryAddress shopOrderDeliveryAddress = shopOrderDeliveryAddressService.selectByOrderId(shopOrderId);
|
||||
ShopStoreSameCityTransportBase shopStoreSameCityTransportBase = shopStoreSameCityTransportBaseService.getShopStoreSameCityTransportBaseById(storeId.longValue());
|
||||
if (shopStoreBase == null || shopStoreInfo == null || shopOrderDeliveryAddress == null || shopStoreSameCityTransportBase == null) {
|
||||
logger.error("构建顺丰订单失败:无法获取店铺信息,订单ID={},storeId={}", shopOrderId, storeId);
|
||||
logger.error("无法获取店铺信息!");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (shopStoreSameCityTransportBase == null) {
|
||||
logger.error("请配置同城配送设置!");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -8676,11 +8556,11 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
String shopId = "3243279847393";
|
||||
//3269768224353 到时启用这个正式店铺 type:便利店
|
||||
Integer businessType = 6;// 生鲜分类
|
||||
if (CommonConstant.Enable.equals(enable_sf_express)) {//开启正式配送服务的时候
|
||||
if (enable_sf_express.equals(CommonConstant.Enable)) {//开启正式配送服务的时候
|
||||
// 顺丰同城业务员给的店铺id
|
||||
shopId = shopStoreSameCityTransportBase.getShop_id();
|
||||
if (StrUtil.isBlank(shopId)) {
|
||||
logger.error("构建顺丰订单失败:请联系顺丰同城配置店铺ID,订单ID={},storeId={}", shopOrderId, storeId);
|
||||
logger.error("请联系顺丰同城配置店铺ID!");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -8702,8 +8582,8 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
sfCreateOrderReq.setVersion(19);
|
||||
sfCreateOrderReq.setReturn_flag(511);
|
||||
|
||||
Integer totalProductQuantity = 0;
|
||||
Integer productTypeCount = shopOrderItemList.size();
|
||||
Integer productNum = 0;
|
||||
Integer productTypeNum = shopOrderItemList.size();
|
||||
|
||||
// 订单详情信息
|
||||
SFOrderDetailReq orderDetail = new SFOrderDetailReq();
|
||||
@ -8712,35 +8592,24 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
List<SFOrderProductDetailReq> orderProductList = new ArrayList<>();
|
||||
|
||||
for (ShopOrderItem shopOrderItem : shopOrderItemList) {
|
||||
totalProductQuantity += shopOrderItem.getOrder_item_quantity();
|
||||
productNum += shopOrderItem.getOrder_item_quantity();
|
||||
// 产品详情
|
||||
SFOrderProductDetailReq orderProductDetail = new SFOrderProductDetailReq();
|
||||
orderProductDetail.setProduct_id(shopOrderItem.getProduct_id());
|
||||
orderProductDetail.setProduct_name(shopOrderItem.getItem_name());
|
||||
orderProductDetail.setProduct_num(shopOrderItem.getOrder_item_quantity());
|
||||
// 单个商品金额=单价*数量,单位分
|
||||
BigDecimal itemPriceDecimal = shopOrderItem.getOrder_item_unit_price()
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.multiply(BigDecimal.valueOf(shopOrderItem.getOrder_item_quantity()));
|
||||
Integer itemPrice = itemPriceDecimal.intValue();
|
||||
// 单个商品金额=数量*单价,单位分
|
||||
Integer itemPrice = shopOrderItem.getOrder_item_unit_price().multiply(BigDecimal.valueOf(shopOrderItem.getOrder_item_quantity())).multiply(BigDecimal.valueOf(100)).intValue();
|
||||
orderProductDetail.setProduct_price(itemPrice);
|
||||
orderProductList.add(orderProductDetail);
|
||||
|
||||
// 记录商品详情日志,便于部署后排查问题
|
||||
logger.debug("订单{}商品详情:商品ID={}, 商品名称={}, 数量={}, 单价(分)={}, 小计(分)={}",
|
||||
shopOrderId,
|
||||
shopOrderItem.getProduct_id(),
|
||||
shopOrderItem.getItem_name(),
|
||||
shopOrderItem.getOrder_item_quantity(),
|
||||
shopOrderItem.getOrder_item_unit_price().multiply(BigDecimal.valueOf(100)).intValue(),
|
||||
itemPrice);
|
||||
}
|
||||
|
||||
orderDetail.setProduct_type(businessType); // 店铺主营商品分类,参考:https://commit-openic.sf-express.com/#/apidoc
|
||||
orderDetail.setTotal_price(shopOrderBase.getOrder_payment_amount().multiply(BigDecimal.valueOf(100)).intValue()); // 单位分
|
||||
orderDetail.setWeight_gram(0); // 重量一律传 0kg 先,谢总本地运营商协商好的
|
||||
orderDetail.setProduct_num(totalProductQuantity); //物品个数
|
||||
orderDetail.setProduct_type_num(productTypeCount); //物品种类个数
|
||||
orderDetail.setProduct_num(productNum); //物品个数
|
||||
orderDetail.setProduct_type_num(productTypeNum); //物品种类个数
|
||||
|
||||
|
||||
// 订单里的所有商品列表
|
||||
orderDetail.setProduct_detail(orderProductList);
|
||||
@ -8754,11 +8623,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
|
||||
// 店铺信息(发货人信息)
|
||||
Pair<Boolean, StandardAddressDTO> pairShopAddr = shopStoreBaseService.checkStoreAddress(shopStoreBase);
|
||||
if (!pairShopAddr.getFirst()) {
|
||||
logger.error("构建顺丰订单失败:店铺地址校验失败,订单ID={},storeId={}", shopOrderId, storeId);
|
||||
return null;
|
||||
}
|
||||
|
||||
shop.setShop_name(shopStoreBase.getStore_name());
|
||||
shop.setShop_phone(shopStoreInfo.getStore_tel());
|
||||
shop.setShop_address(pairShopAddr.getSecond().getFullAddress());
|
||||
@ -8767,11 +8631,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
|
||||
// 收货人信息
|
||||
Pair<Boolean, StandardAddressDTO> pairReceiveAddr = shopOrderDeliveryAddressService.checkAddress(shopOrderDeliveryAddress);
|
||||
if (!pairReceiveAddr.getFirst()) {
|
||||
logger.error("构建顺丰订单失败:收货地址校验失败,订单ID={},storeId={}", shopOrderId, storeId);
|
||||
return null;
|
||||
}
|
||||
|
||||
receive.setUser_name(shopOrderDeliveryAddress.getDa_name());
|
||||
receive.setUser_phone(shopOrderDeliveryAddress.getDa_mobile());
|
||||
receive.setUser_address(pairReceiveAddr.getSecond().getFullAddress());
|
||||
@ -8796,11 +8655,6 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
sfCreateOrderReq.setShop(shop);
|
||||
sfCreateOrderReq.setReceive(receive);
|
||||
|
||||
// 记录完整的订单信息,便于部署后排查问题
|
||||
logger.info("成功构建顺丰订单:订单ID={}, 店铺ID={}, 顺丰同城店铺ID={}, 商品种类数={}, 商品总数={}, 总价(分)={}",
|
||||
shopOrderId, storeId, shopId, productTypeCount, totalProductQuantity,
|
||||
shopOrderBase.getOrder_payment_amount().multiply(BigDecimal.valueOf(100)).intValue());
|
||||
|
||||
return sfCreateOrderReq;
|
||||
}
|
||||
|
||||
@ -9185,6 +9039,38 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 预处理发货订单超时消息(发到 mq 里,触发超时事件,发出推送消息)
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param orderId 订单ID
|
||||
* @param expireSeconds 过期时间(秒)
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
// @Async
|
||||
// @Override
|
||||
// public Boolean preSendExpiredSFOrderPushMessage(Integer storeId, String orderId, Long expireSeconds) {
|
||||
// try {
|
||||
// // 构建延迟消息内容
|
||||
// JSONObject jsonObject = new JSONObject();
|
||||
// jsonObject.put("category", MqConstant.DEAD_EVENT_CATE_ORDER_EXPIRED); // 消息分类:1-订单超时消息
|
||||
// jsonObject.put("orderId", orderId); // 订单ID
|
||||
// jsonObject.put("storeId", storeId); // 店铺ID
|
||||
// jsonObject.put("title", "有一笔已超时的订单!"); // 消息标题
|
||||
// jsonObject.put("message", "您有一笔已超时的订单[" + orderId + "],请及时处理。"); // 消息内容
|
||||
//
|
||||
// // 发送延迟消息
|
||||
// mqMessageService.sendDelayMessage(jsonObject.toString(), expireSeconds * 1000); // 转换为毫秒
|
||||
//
|
||||
// return true;
|
||||
// } catch (Exception e) {
|
||||
// log.error("发送延迟订单超时消息失败,店铺ID:{},订单ID:{},过期时间:{}秒",
|
||||
// storeId, orderId, expireSeconds, e);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 取货单号格式化
|
||||
*
|
||||
@ -9226,11 +9112,11 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
// 确保比例在合理范围 [0, 100]
|
||||
storeSplitRatio = storeSplitRatio.max(BigDecimal.ZERO).min(new BigDecimal(100));
|
||||
storeSplitRatio = storeSplitRatio.max(BigDecimal.ZERO).min(new BigDecimal("100"));
|
||||
|
||||
// 分账金额 = 支付金额 × 平台和代理商分账比例 ÷ 100 (将百分比转换为小数)
|
||||
BigDecimal result = pendingAmount.multiply(new BigDecimal(100).subtract(storeSplitRatio))
|
||||
.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN); // 保留两位小数
|
||||
BigDecimal result = pendingAmount.multiply(new BigDecimal("100").subtract(storeSplitRatio))
|
||||
.divide(new BigDecimal("100"), 2, RoundingMode.HALF_DOWN); // 保留两位小数
|
||||
|
||||
logger.debug("计算分账金额: storeId={}, pendingAmount={}, ratio={}, result={}",
|
||||
storeId, pendingAmount, storeSplitRatio, result);
|
||||
|
||||
@ -229,127 +229,81 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
|
||||
/**
|
||||
* 更改商家订单的状态,出库状态,发货状态,并写入订单状态更改日志
|
||||
*
|
||||
* @param orderId 订单ID
|
||||
* @param orderStatus 订单状态,约定0值不更改
|
||||
* @param orderId
|
||||
* @param orderStatus 约定0值不更改
|
||||
* @param orderIsOutStatus 出库状态,约定0值不更改
|
||||
* @param orderIsShippedStatus 发货状态,约定0值不更改
|
||||
* @return Boolean 是否更新成功
|
||||
* @return
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
public Boolean changeOrderStatus(String orderId, Integer orderStatus, Integer orderIsOutStatus, Integer orderIsShippedStatus) {
|
||||
try {
|
||||
// 参数校验
|
||||
if (orderId == null || orderStatus == null) {
|
||||
logger.warn("[订单状态变更] 参数校验失败: orderId或orderStatus为空, orderId={}, orderStatus={}", orderId, orderStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取订单信息
|
||||
ShopOrderInfo shopOrderInfo = getById(orderId);
|
||||
if (shopOrderInfo == null) {
|
||||
logger.warn("[订单状态变更] 未找到订单信息: orderId={}", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug("[订单状态变更] 开始处理订单状态变更: orderId={}, currentStatus={}, newStatus={}, outStatus={}, shippedStatus={}",
|
||||
orderId, shopOrderInfo.getOrder_state_id(), orderStatus, orderIsOutStatus, orderIsShippedStatus);
|
||||
|
||||
Integer preOrderStatus = shopOrderInfo.getOrder_state_id();
|
||||
|
||||
int paramsCnt = 0;
|
||||
UpdateWrapper<ShopOrderInfo> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("order_id", orderId);
|
||||
|
||||
// 更新订单状态
|
||||
if (orderStatus > 0) {
|
||||
updateWrapper.set("order_state_id", orderStatus);
|
||||
|
||||
// 已签收或已完成,更改两个时间
|
||||
if (StateCode.ORDER_STATE_RECEIVED == orderStatus.intValue() || orderStatus == StateCode.ORDER_STATE_FINISH) {
|
||||
updateWrapper.set("order_deal_time", System.currentTimeMillis());
|
||||
updateWrapper.set("order_qs_time", new Date());
|
||||
}
|
||||
|
||||
paramsCnt++;
|
||||
logger.debug("[订单状态变更] 添加订单状态更新条件: orderId={}, status={}", orderId, orderStatus);
|
||||
}
|
||||
|
||||
// 更新出库状态
|
||||
if (orderIsOutStatus != null && orderIsOutStatus > 0 &&
|
||||
!ObjectUtil.equal(shopOrderInfo.getOrder_is_out(), orderIsOutStatus)) {
|
||||
updateWrapper.set("order_is_out", orderIsOutStatus);
|
||||
paramsCnt++;
|
||||
logger.debug("[订单状态变更] 添加出库状态更新条件: orderId={}, outStatus={}", orderId, orderIsOutStatus);
|
||||
}
|
||||
|
||||
// 更新发货状态
|
||||
if (orderIsShippedStatus != null && orderIsShippedStatus > 0 &&
|
||||
!ObjectUtil.equal(shopOrderInfo.getOrder_is_shipped(), orderIsShippedStatus)) {
|
||||
updateWrapper.set("order_is_shipped", orderIsShippedStatus);
|
||||
paramsCnt++;
|
||||
logger.debug("[订单状态变更] 添加发货状态更新条件: orderId={}, shippedStatus={}", orderId, orderIsShippedStatus);
|
||||
}
|
||||
|
||||
// 检查是否有需要更新的字段
|
||||
if (paramsCnt <= 0) {
|
||||
logger.info("[订单状态变更] 无需要更新的字段: orderId={}", orderId);
|
||||
// 无修改的状态
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行订单信息更新
|
||||
logger.debug("[订单状态变更] 执行订单信息更新: orderId={}, updateFields={}", orderId, paramsCnt);
|
||||
if (!update(updateWrapper)) {
|
||||
logger.error("[订单状态变更] 订单信息更新失败: orderId={}", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新订单基础信息中的状态
|
||||
UpdateWrapper<ShopOrderBase> updateShopOrderBaseWrapper = new UpdateWrapper<>();
|
||||
updateShopOrderBaseWrapper.eq("order_id", orderId);
|
||||
if (orderStatus > 0) {
|
||||
updateShopOrderBaseWrapper.set("order_state_id", orderStatus);
|
||||
logger.debug("[订单状态变更] 执行订单基础信息更新: orderId={}, status={}", orderId, orderStatus);
|
||||
if (!shopOrderBaseService.update(updateShopOrderBaseWrapper)) {
|
||||
logger.error("[订单状态变更] 订单基础信息更新失败: orderId={}", orderId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 写入订单状态更改日志
|
||||
logger.debug("[订单状态变更] 写入订单状态变更日志: orderId={}, preStatus={}, newStatus={}", orderId, preOrderStatus, orderStatus);
|
||||
ShopOrderStateLog shopOrderStateLog = new ShopOrderStateLog();
|
||||
shopOrderStateLog.setOrder_id(orderId);
|
||||
shopOrderStateLog.setOrder_state_is_sync(0);
|
||||
shopOrderStateLog.setOrder_state_id(orderStatus);
|
||||
shopOrderStateLog.setOrder_state_time(new Date());
|
||||
shopOrderStateLog.setOrder_state_pre_id(preOrderStatus);
|
||||
shopOrderStateLog.setOrder_state_type(shopBaseStateCodeService.getText(orderStatus, null));
|
||||
shopOrderStateLog.setOrder_state_note(CommonUtil.getOrderStateNote(preOrderStatus, orderStatus));
|
||||
shopOrderStateLog.setUser_id(0);
|
||||
shopOrderStateLog.setUser_nickname("SfExpress");
|
||||
|
||||
boolean logResult = shopOrderStateLogService.add(shopOrderStateLog);
|
||||
if (logResult) {
|
||||
logger.info("[订单状态变更] 订单状态变更成功: orderId={}, preStatus={}, newStatus={}", orderId, preOrderStatus, orderStatus);
|
||||
|
||||
// 远程调用 更改交易订单状态
|
||||
logger.debug("[订单状态变更] 调用支付服务更新交易订单状态: orderId={}, status={}", orderId, orderStatus);
|
||||
if (!payService.changePayConsumeTradeState(orderId, orderStatus, 0)) {
|
||||
logger.error("[订单状态变更] 远程调用更改交易订单状态失败: orderId={}", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.error("[订单状态变更] 订单状态日志写入失败: orderId={}", orderId);
|
||||
}
|
||||
|
||||
return logResult;
|
||||
} catch (Exception e) {
|
||||
logger.error("[订单状态变更] 处理过程中发生异常: orderId={}, orderStatus={}, outStatus={}, shippedStatus={}",
|
||||
orderId, orderStatus, orderIsOutStatus, orderIsShippedStatus, e);
|
||||
if (orderId == null || orderStatus == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShopOrderInfo shopOrderInfo = getById(orderId);
|
||||
if (shopOrderInfo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Integer preOrderStatus = shopOrderInfo.getOrder_state_id();
|
||||
|
||||
int paramsCnt = 0;
|
||||
UpdateWrapper<ShopOrderInfo> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("order_id", orderId);
|
||||
if (orderStatus > 0) {
|
||||
updateWrapper.set("order_state_id", orderStatus);
|
||||
paramsCnt++;
|
||||
}
|
||||
|
||||
if (orderIsOutStatus > 0 && !shopOrderInfo.getOrder_is_out().equals(orderIsOutStatus)) {
|
||||
updateWrapper.set("order_is_out", orderStatus);
|
||||
paramsCnt++;
|
||||
}
|
||||
|
||||
if (orderStatus > 0 && !shopOrderInfo.getOrder_is_shipped().equals(orderIsShippedStatus)) {
|
||||
updateWrapper.set("order_is_shipped", orderIsShippedStatus);
|
||||
paramsCnt++;
|
||||
}
|
||||
|
||||
if (paramsCnt <= 0) {
|
||||
// 无修改的状态
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!update(updateWrapper)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateWrapper<ShopOrderBase> updateShopOrderBaseWrapper = new UpdateWrapper<>();
|
||||
updateShopOrderBaseWrapper.eq("order_id", orderId);
|
||||
if (orderStatus > 0) {
|
||||
updateShopOrderBaseWrapper.set("order_state_id", orderStatus);
|
||||
if (!shopOrderBaseService.update(updateShopOrderBaseWrapper)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 远程调用 更改交易订单状态
|
||||
if (!payService.changePayConsumeTradeState(orderId, orderStatus, 0)) {
|
||||
logger.error("远程调用更改交易订单状态失败!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 写入订单状态更改日志
|
||||
ShopOrderStateLog shopOrderStateLog = new ShopOrderStateLog();
|
||||
shopOrderStateLog.setOrder_id(orderId);
|
||||
shopOrderStateLog.setOrder_state_is_sync(0);
|
||||
shopOrderStateLog.setOrder_state_id(orderStatus);
|
||||
shopOrderStateLog.setOrder_state_time(new Date());
|
||||
shopOrderStateLog.setOrder_state_pre_id(preOrderStatus);
|
||||
shopOrderStateLog.setOrder_state_type(shopBaseStateCodeService.getText(orderStatus, null));
|
||||
shopOrderStateLog.setOrder_state_note(CommonUtil.getOrderStateNote(preOrderStatus, orderStatus));
|
||||
shopOrderStateLog.setUser_id(0);
|
||||
shopOrderStateLog.setUser_nickname("SfExpress");
|
||||
|
||||
return shopOrderStateLogService.add(shopOrderStateLog);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -14,10 +14,8 @@ 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.core.conditions.update.UpdateWrapper;
|
||||
import com.suisung.mall.common.modules.order.ShopOrderBase;
|
||||
import com.suisung.mall.common.modules.order.ShopOrderLkl;
|
||||
import com.suisung.mall.common.utils.CheckUtil;
|
||||
import com.suisung.mall.common.utils.DateTimeUtils;
|
||||
import com.suisung.mall.common.utils.JsonUtil;
|
||||
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
|
||||
@ -52,6 +50,7 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
@Resource
|
||||
private ShopOrderDataService shopOrderDataService;
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean addOrUpdateByStoreOrder(ShopOrderLkl record) {
|
||||
if (record == null
|
||||
@ -123,157 +122,97 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
* "merchantNo": "8226330599900LN"
|
||||
* }
|
||||
* }
|
||||
* @return Boolean 是否保存或更新成功
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean addOrUpdateByLklPayDataJson(JSONObject lklPayReqAndRespJson) {
|
||||
if (lklPayReqAndRespJson == null) {
|
||||
log.warn("[拉卡拉订单保存] 参数为空,无法保存拉卡拉订单记录");
|
||||
log.warn("参数为空,无法保存拉卡拉订单记录");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.debug("[拉卡拉订单保存] 开始处理拉卡拉支付请求和响应数据: {}", lklPayReqAndRespJson);
|
||||
log.debug("拉卡拉支付请求和响应数据 body:{}", lklPayReqAndRespJson);
|
||||
try {
|
||||
|
||||
// 获取请求体和响应体
|
||||
JSONObject reqDataJson = lklPayReqAndRespJson.getJSONObject("req");// 下划线命名
|
||||
JSONObject reqDataJson = lklPayReqAndRespJson.getJSONObject("req");// 驼峰命名
|
||||
JSONObject respDataJson = JSONUtil.parseObj(lklPayReqAndRespJson.getByPath("resp.resp_data"));// 下划线命名
|
||||
|
||||
if (reqDataJson == null || respDataJson == null) {
|
||||
log.error("[拉卡拉订单保存] 请求或响应数据中的 req_data / resp_data 为空");
|
||||
log.error("请求或响应数据中的 req_data / resp_data 为空");
|
||||
return false;
|
||||
}
|
||||
log.debug("[拉卡拉订单保存] 解析请求和响应数据完成");
|
||||
|
||||
// 提取订单号并校验
|
||||
String orderId = JsonUtil.getJsonValueSmart(respDataJson, "out_trade_no");
|
||||
if (StringUtils.isBlank(orderId)) {
|
||||
log.error("[拉卡拉订单保存] 订单ID为空,无法保存拉卡拉支付记录");
|
||||
log.error("订单ID为空,无法保存拉卡拉支付记录");
|
||||
return false;
|
||||
}
|
||||
log.debug("[拉卡拉订单保存] 解析订单ID: {}", orderId);
|
||||
|
||||
ShopOrderBase shopOrderBase = shopOrderBaseService.get(orderId);
|
||||
if (shopOrderBase == null) {
|
||||
log.error("[拉卡拉订单保存] 订单不存在,无法保存拉卡拉支付记录: orderId={}", orderId);
|
||||
log.error("订单不存在,无法保存拉卡拉支付记录");
|
||||
return false;
|
||||
}
|
||||
log.debug("[拉卡拉订单保存] 获取订单基础信息完成: storeId={}", shopOrderBase.getStore_id());
|
||||
|
||||
ShopOrderLkl record = new ShopOrderLkl();
|
||||
record.setOrder_id(orderId);
|
||||
String outSeparateNo = JsonUtil.getJsonValueSmart(reqDataJson, "outTradeNo");
|
||||
|
||||
// 平台最低内部配送费
|
||||
Integer shoppingFeeInner = Convert.toInt(JsonUtil.getJsonValueSmart(reqDataJson, "shopping_fee_inner"));
|
||||
if (shoppingFeeInner == null) {
|
||||
shoppingFeeInner = 0;
|
||||
}
|
||||
record.setOut_separate_no(outSeparateNo);
|
||||
log.debug("[拉卡拉订单保存] 设置订单ID和分离订单号: orderId={} outSeparateNo={}", orderId, outSeparateNo);
|
||||
|
||||
// 设置请求内容
|
||||
|
||||
// 订单金额安全处理
|
||||
Integer amount = JsonUtil.getJsonValueSmart(reqDataJson, "totalAmount", Integer.class);
|
||||
if (amount == null) {
|
||||
log.error("[拉卡拉订单保存] 订单{}金额无效: amount={}", orderId, amount);
|
||||
log.error("订单{}金额无效: {}", orderId, amount);
|
||||
return false;
|
||||
}
|
||||
record.setTotal_amt(amount); // 应支付总金额
|
||||
log.debug("[拉卡拉订单保存] 设置订单金额: amount={}分", amount);
|
||||
|
||||
record.setAccount_type(JsonUtil.getJsonValueSmart(reqDataJson, "accountType"));
|
||||
record.setTrans_type(JsonUtil.getJsonValueSmart(reqDataJson, "transType"));
|
||||
record.setNotify_url(JsonUtil.getJsonValueSmart(reqDataJson, "notifyUrl"));
|
||||
record.setLkl_merchant_no(JsonUtil.getJsonValueSmart(reqDataJson, "merchantNo"));
|
||||
record.setLkl_term_no(JsonUtil.getJsonValueSmart(reqDataJson, "termNo"));
|
||||
record.setLkl_req(JSONUtil.toJsonStr(reqDataJson));
|
||||
|
||||
// 设置响应内容
|
||||
record.setLkl_log_no(JsonUtil.getJsonValueSmart(respDataJson, "log_no"));
|
||||
record.setLkl_trade_no(JsonUtil.getJsonValueSmart(respDataJson, "trade_no"));
|
||||
record.setLkl_resp(JSONUtil.toJsonStr(respDataJson));
|
||||
|
||||
// 关键数据:获取店铺ID,分账比例用到
|
||||
Integer storeId = shopOrderBase.getStore_id();
|
||||
|
||||
record.setStore_id(Convert.toStr(storeId));
|
||||
//平台内部配送费
|
||||
record.setShopping_fee_inner(shoppingFeeInner);
|
||||
log.debug("[拉卡拉订单保存] 设置店铺ID: storeId={}", storeId);
|
||||
|
||||
// 运费和商家分账比例
|
||||
BigDecimal shipperFee = shopOrderDataService.getOrderShippingFee(orderId); // 运费获取
|
||||
if (shipperFee != null) {
|
||||
int shipperFeeInCents = shipperFee.multiply(BigDecimal.valueOf(100)).intValue(); // 运费,单位:分
|
||||
record.setShopping_fee(shipperFeeInCents);
|
||||
log.debug("[拉卡拉订单保存] 商家设置运费: 元={} 分={}", shipperFee, shipperFeeInCents);
|
||||
} else {
|
||||
log.debug("[拉卡拉订单保存] 未获取到运费信息");
|
||||
}
|
||||
BigDecimal shipperFee = shopOrderDataService.getOrderShippingFee(orderId);
|
||||
record.setShopping_fee(shipperFee.multiply(BigDecimal.valueOf(100)).intValue()); // 运费,单位:分
|
||||
record.setSplit_ratio(shopStoreBaseService.getStoreSplitRatio(storeId, false)); // 商家分账比例
|
||||
|
||||
BigDecimal splitRatio = shopStoreBaseService.getStoreSplitRatio(storeId, false); // 商家分账比例计算
|
||||
record.setSplit_ratio(splitRatio);
|
||||
log.debug("[拉卡拉订单保存] 设置分账比例: ratio={}", splitRatio);
|
||||
|
||||
// 设置其他请求字段
|
||||
String accountType = JsonUtil.getJsonValueSmart(reqDataJson, "accountType");
|
||||
String transType = JsonUtil.getJsonValueSmart(reqDataJson, "transType");
|
||||
String notifyUrl = JsonUtil.getJsonValueSmart(reqDataJson, "notifyUrl");
|
||||
String receiveNotifyUrl = JsonUtil.getJsonValueSmart(reqDataJson, "complete_notify_url");
|
||||
String merchantNo = JsonUtil.getJsonValueSmart(reqDataJson, "merchantNo");
|
||||
String termNo = JsonUtil.getJsonValueSmart(reqDataJson, "termNo");
|
||||
|
||||
record.setAccount_type(accountType);
|
||||
record.setTrans_type(transType);
|
||||
record.setNotify_url(notifyUrl);
|
||||
record.setReceive_notify_url(receiveNotifyUrl);
|
||||
record.setLkl_merchant_no(merchantNo);
|
||||
record.setLkl_term_no(termNo);
|
||||
|
||||
log.debug("[拉卡拉订单保存] 设置请求字段: accountType={} transType={} merchantNo={} termNo={}",
|
||||
accountType, transType, merchantNo, termNo);
|
||||
|
||||
String reqJsonStr = JSONUtil.toJsonStr(reqDataJson);
|
||||
record.setLkl_req(reqJsonStr);
|
||||
log.debug("[拉卡拉订单保存] 设置请求JSON,长度={}", reqJsonStr != null ? reqJsonStr.length() : 0);
|
||||
|
||||
// 设置响应内容
|
||||
String logNo = JsonUtil.getJsonValueSmart(respDataJson, "log_no");
|
||||
record.setLkl_log_no(logNo);
|
||||
log.debug("[拉卡拉订单保存] 设置流水号: logNo={}", logNo);
|
||||
|
||||
String tradeNo = JsonUtil.getJsonValueSmart(respDataJson, "trade_no");
|
||||
record.setLkl_trade_no(tradeNo);
|
||||
log.debug("[拉卡拉订单保存] 设置交易号: tradeNo={}", tradeNo);
|
||||
|
||||
String respJsonStr = JSONUtil.toJsonStr(respDataJson);
|
||||
record.setLkl_resp(respJsonStr);
|
||||
log.debug("[拉卡拉订单保存] 设置响应JSON,长度={}", respJsonStr != null ? respJsonStr.length() : 0);
|
||||
|
||||
log.debug("[拉卡拉订单保存] 调用addOrUpdateByStoreOrder方法保存记录: orderId={}", orderId);
|
||||
Boolean result = addOrUpdateByStoreOrder(record);
|
||||
if (result) {
|
||||
log.info("[拉卡拉订单保存] 拉卡拉订单记录保存成功: orderId={}", orderId);
|
||||
} else {
|
||||
log.error("[拉卡拉订单保存] 拉卡拉订单记录保存失败: orderId={}", orderId);
|
||||
}
|
||||
return result;
|
||||
return addOrUpdateByStoreOrder(record);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉订单保存] 新增拉卡拉支付记录出错", e);
|
||||
log.error("新增拉卡拉支付记录出错", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据拉卡拉支付异步回调通知数据保存或更新拉卡拉订单记录
|
||||
* 该方法用于处理拉卡拉支付平台发送的支付通知,将通知中的数据保存到shop_order_lkl表中
|
||||
*
|
||||
* @param lklPayNotifyDataJson 拉卡拉支付通知的JSON数据
|
||||
* @return Boolean 是否保存或更新成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean addOrUpdateByLklPayNotifyDataJson(JSONObject lklPayNotifyDataJson) {
|
||||
if (lklPayNotifyDataJson == null) {
|
||||
log.warn("[拉卡拉订单更新] 参数为空,无法保存拉卡拉支付通知记录");
|
||||
log.warn("参数为空,无法保存拉卡拉支付通知记录");
|
||||
return false;
|
||||
}
|
||||
|
||||
log.debug("[拉卡拉订单更新] 开始处理拉卡拉支付通知回调: {}", lklPayNotifyDataJson);
|
||||
log.debug("拉卡拉支付通知回调 body:{}", lklPayNotifyDataJson);
|
||||
try {
|
||||
// 获取订单ID
|
||||
|
||||
String orderId = lklPayNotifyDataJson.getStr("out_trade_no");
|
||||
if (StringUtils.isBlank(orderId)) {
|
||||
log.warn("[拉卡拉订单更新] 订单ID为空,无法保存拉卡拉支付通知记录");
|
||||
log.warn("订单ID为空,无法保存拉卡拉支付通知记录");
|
||||
return false;
|
||||
}
|
||||
log.debug("[拉卡拉订单更新] 解析订单ID: {}", orderId);
|
||||
|
||||
ShopOrderLkl record = new ShopOrderLkl();
|
||||
record.setOrder_id(orderId);
|
||||
@ -281,69 +220,24 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
// 设置必填字段并校验
|
||||
String logNo = lklPayNotifyDataJson.getStr("log_no");
|
||||
if (StringUtils.isBlank(logNo)) {
|
||||
log.warn("[拉卡拉订单更新] log_no为空,无法保存拉卡拉支付通知记录: orderId={}", orderId);
|
||||
log.warn("log_no 为空,无法保存拉卡拉支付通知记录");
|
||||
return false;
|
||||
}
|
||||
record.setLkl_log_no(logNo);
|
||||
log.debug("[拉卡拉订单更新] 设置流水号: {}", logNo);
|
||||
|
||||
// 设置日期字段
|
||||
String logDate = DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyyMMdd");
|
||||
record.setLkl_log_date(logDate);
|
||||
log.debug("[拉卡拉订单更新] 设置日期字段: {}", logDate);
|
||||
record.setLkl_log_date(DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd"));
|
||||
|
||||
// 设置可选字段
|
||||
String tradeNo = lklPayNotifyDataJson.getStr("trade_no");
|
||||
String tradeStatus = lklPayNotifyDataJson.getStr("trade_status");
|
||||
String accTradeNo = lklPayNotifyDataJson.getStr("acc_trade_no");
|
||||
record.setLkl_trade_no(tradeNo);
|
||||
record.setTrade_status(tradeStatus);
|
||||
record.setWx_transaction_id(accTradeNo); //账户端交易订单号 对应微信的用户交易单号
|
||||
log.debug("[拉卡拉订单更新] 设置可选字段: tradeNo={} accTradeNo={} tradeStatus={}", tradeNo, accTradeNo, tradeStatus);
|
||||
|
||||
// 新增的订单字段,lkl_sub_log_no,out_separate_no,split_amt 四个字段无值,就给主单的值
|
||||
String outSeparateNo = JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "out_separate_no");
|
||||
if (CheckUtil.isEmpty(outSeparateNo)) {
|
||||
outSeparateNo = orderId;
|
||||
}
|
||||
record.setOut_separate_no(outSeparateNo);
|
||||
|
||||
String lklSubTradeNo = JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "lkl_sub_trade_no");
|
||||
if (CheckUtil.isEmpty(lklSubTradeNo)) {
|
||||
lklSubTradeNo = tradeNo;
|
||||
}
|
||||
record.setLkl_sub_trade_no(lklSubTradeNo);
|
||||
|
||||
String lklSubLogNo = JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "lkl_sub_log_no");
|
||||
if (CheckUtil.isEmpty(lklSubLogNo)) {
|
||||
lklSubLogNo = logNo;
|
||||
}
|
||||
record.setLkl_sub_log_no(lklSubLogNo);
|
||||
|
||||
Integer splitAmt = JsonUtil.getJsonValueSmart(lklPayNotifyDataJson, "split_amt", Integer.class);
|
||||
if (CheckUtil.isEmpty(splitAmt)) {
|
||||
splitAmt = record.getTotal_amt();
|
||||
}
|
||||
record.setSplit_amt(splitAmt);
|
||||
|
||||
log.debug("[拉卡拉订单更新] 设置订单字段: outSeparateNo={} lklSubTradeNo={} lklSubLogNo={} splitAmt={}",
|
||||
outSeparateNo, lklSubTradeNo, lklSubLogNo, splitAmt);
|
||||
record.setLkl_trade_no(lklPayNotifyDataJson.getStr("trade_no"));
|
||||
record.setTrade_status(lklPayNotifyDataJson.getStr("trade_status"));
|
||||
|
||||
// 安全地设置响应内容
|
||||
String notifyResp = JSONUtil.toJsonStr(lklPayNotifyDataJson);
|
||||
record.setLkl_notify_resp(notifyResp);
|
||||
log.debug("[拉卡拉订单更新] 设置通知响应内容,长度={}", notifyResp != null ? notifyResp.length() : 0);
|
||||
record.setLkl_notify_resp(JSONUtil.toJsonStr(lklPayNotifyDataJson));
|
||||
|
||||
log.debug("[拉卡拉订单更新] 调用addOrUpdateByStoreOrder方法保存记录: orderId={}", orderId);
|
||||
Boolean result = addOrUpdateByStoreOrder(record);
|
||||
if (result) {
|
||||
log.info("[拉卡拉订单更新] 拉卡拉订单记录保存成功: orderId={}", orderId);
|
||||
} else {
|
||||
log.error("[拉卡拉订单更新] 拉卡拉订单记录保存失败: orderId={}", orderId);
|
||||
}
|
||||
return result;
|
||||
return addOrUpdateByStoreOrder(record);
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉订单更新] 修改拉卡拉支付通知记录出错", e);
|
||||
log.error("修改拉卡拉支付通知记录出错", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -379,221 +273,4 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
return CollectionUtil.newArrayList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据店铺Id、订单编号查询一条记录
|
||||
*
|
||||
* @param storeId
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ShopOrderLkl getByStoreIdAndOrderId(Integer storeId, String orderId) {
|
||||
if (CheckUtil.isEmpty(storeId) || StringUtils.isBlank(orderId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
QueryWrapper<ShopOrderLkl> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("store_id", storeId).eq("order_id", orderId).orderByAsc("id");
|
||||
|
||||
if (CheckUtil.isEmpty(storeId)) {
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
}
|
||||
|
||||
return findOne(queryWrapper);
|
||||
} catch (Exception e) {
|
||||
log.error("getByStoreIdAndOrderId 查询异常, orderId: {}, storeId: {}", orderId, storeId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商户号、子单交易流水号、子单对账单流水号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param lklSubTradeNo 原拉卡拉交易流水号
|
||||
* @param lklSubLogNo 原拉卡拉对账单流水号
|
||||
* @return ShopOrderLkl 拉卡拉订单记录
|
||||
*/
|
||||
@Override
|
||||
public ShopOrderLkl getByLklMchNoAndSubTradeNoAndSubLogNo(String lklMerchantNo, String lklSubTradeNo, String lklSubLogNo) {
|
||||
// 检查参数是否全部为空
|
||||
if (StringUtils.isAllBlank(lklMerchantNo, lklSubTradeNo, lklSubLogNo)) {
|
||||
log.warn("[拉卡拉订单查询] 参数校验失败:所有查询条件均为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("[拉卡拉订单查询] 开始查询, 商户号={}, 子订单交易号={}, 子订单对账流水号={}",
|
||||
lklMerchantNo, lklSubTradeNo, lklSubLogNo);
|
||||
|
||||
QueryWrapper<ShopOrderLkl> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.orderByAsc("id");
|
||||
|
||||
// 根据非空参数构建查询条件
|
||||
if (StrUtil.isNotBlank(lklMerchantNo)) {
|
||||
queryWrapper.eq("lkl_merchant_no", lklMerchantNo);
|
||||
log.debug("[拉卡拉订单查询] 添加商户号查询条件: {}", lklMerchantNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklSubTradeNo)) {
|
||||
queryWrapper.eq("lkl_sub_trade_no", lklSubTradeNo);
|
||||
log.debug("[拉卡拉订单查询] 添加子订单交易号查询条件: {}", lklSubTradeNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklSubLogNo)) {
|
||||
queryWrapper.eq("lkl_sub_log_no", lklSubLogNo);
|
||||
log.debug("[拉卡拉订单查询] 添加子订单对账流水号查询条件: {}", lklSubLogNo);
|
||||
}
|
||||
|
||||
ShopOrderLkl result = findOne(queryWrapper);
|
||||
|
||||
log.debug("[拉卡拉订单查询] 查询完成, 商户号={}, 子订单交易号={}, 子订单对账流水号={}, 查询结果={}",
|
||||
lklMerchantNo, lklSubTradeNo, lklSubLogNo, result != null);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉订单查询] 系统异常, 子订单商户号={}, 交易号={}, 子订单对账流水号={}",
|
||||
lklMerchantNo, lklSubTradeNo, lklSubLogNo, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商户号、交易流水号、对账单流水号查询一条记录
|
||||
*
|
||||
* @param lklMerchantNo 拉卡拉商户号
|
||||
* @param lklReceiveTradeNo 拉卡拉确认收货交易流水号
|
||||
* @param lklReceiveLogNo 拉卡拉确认收货对账单流水号
|
||||
* @return ShopOrderLkl 拉卡拉订单记录
|
||||
*/
|
||||
@Override
|
||||
public ShopOrderLkl getByLklMchNoAndReceiveTradeNoAndReceiveLogNo(String lklMerchantNo, String lklReceiveTradeNo, String lklReceiveLogNo) {
|
||||
// 检查参数是否全部为空
|
||||
if (StringUtils.isAllBlank(lklMerchantNo, lklReceiveTradeNo, lklReceiveLogNo)) {
|
||||
log.warn("[拉卡拉订单查询] 参数校验失败:所有查询条件均为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("[拉卡拉订单查询] 开始查询, 商户号={}, 确认收货交易号={}, 确认收货对账流水号={}",
|
||||
lklMerchantNo, lklReceiveTradeNo, lklReceiveLogNo);
|
||||
|
||||
QueryWrapper<ShopOrderLkl> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.orderByAsc("id");
|
||||
|
||||
// 根据非空参数构建查询条件
|
||||
if (StrUtil.isNotBlank(lklMerchantNo)) {
|
||||
queryWrapper.eq("lkl_merchant_no", lklMerchantNo);
|
||||
log.debug("[拉卡拉订单查询] 添加商户号查询条件: lklMerchantNo={}", lklMerchantNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklReceiveTradeNo)) {
|
||||
queryWrapper.eq("lkl_receive_trade_no", lklReceiveTradeNo);
|
||||
log.debug("[拉卡拉订单查询] 添加交易号查询条件: lklReceiveTradeNo={}", lklReceiveTradeNo);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(lklReceiveLogNo)) {
|
||||
queryWrapper.eq("lkl_receive_log_no", lklReceiveLogNo);
|
||||
log.debug("[拉卡拉订单查询] 添加收货流水号查询条件: lklReceiveLogNo={}", lklReceiveLogNo);
|
||||
}
|
||||
|
||||
ShopOrderLkl result = findOne(queryWrapper);
|
||||
|
||||
log.debug("[拉卡拉订单查询] 查询完成, 商户号={}, 交易号={}, 流水号={}, 查询结果={}",
|
||||
lklMerchantNo, lklReceiveTradeNo, lklReceiveLogNo, result != null);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉订单查询] 系统异常, 商户号={}, 交易号={}, 流水号={}",
|
||||
lklMerchantNo, lklReceiveTradeNo, lklReceiveLogNo, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据确认收货对账单流水号更新分账状态
|
||||
*
|
||||
* @param lklReceiveLogNo 拉卡拉确认收货对账单流水号
|
||||
* @param separateStatus 分账状态:1-已分账;2-未分账;3-分账已失败;
|
||||
* @param separateRemark 分账问题备注;
|
||||
* @return 更新结果 true-成功 false-失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateSeparateStatusByReceiveLogNo(String lklReceiveLogNo, Integer separateStatus, String separateRemark) {
|
||||
// 检查参数是否全部为空
|
||||
if (StringUtils.isBlank(lklReceiveLogNo) || separateStatus == null) {
|
||||
log.warn("[更新分账状态] 参数校验失败:缺少必要参数, lklReceiveLogNo={}, separateStatus={}", lklReceiveLogNo, separateStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
log.info("[更新分账状态] 开始更新分账状态, lklReceiveLogNo={}, separateStatus={}", lklReceiveLogNo, separateStatus);
|
||||
|
||||
UpdateWrapper<ShopOrderLkl> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("lkl_receive_log_no", lklReceiveLogNo);
|
||||
updateWrapper.set("separate_status", separateStatus);
|
||||
if (StrUtil.isNotBlank(separateRemark)) {
|
||||
updateWrapper.set("separate_remark", separateRemark);
|
||||
}
|
||||
|
||||
boolean result = update(updateWrapper);
|
||||
|
||||
if (result) {
|
||||
log.info("[更新分账状态] 分账状态更新成功, lklReceiveLogNo={}, separateStatus={}", lklReceiveLogNo, separateStatus);
|
||||
} else {
|
||||
log.warn("[更新分账状态] 分账状态更新失败,未找到匹配记录, lklReceiveLogNo={}, separateStatus={}", lklReceiveLogNo, separateStatus);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[更新分账状态] 分账状态更新异常, lklReceiveLogNo={}, separateStatus={}", lklReceiveLogNo, separateStatus, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全更新拉卡拉订单记录
|
||||
* <p>
|
||||
* 该方法用于更新拉卡拉订单记录,不会抛出异常,而是在出现错误时返回false。
|
||||
* </p>
|
||||
*
|
||||
* @param record 拉卡拉订单记录
|
||||
* @return 更新结果 true-成功 false-失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean safeUpdate(ShopOrderLkl record) {
|
||||
// 参数校验
|
||||
if (record == null) {
|
||||
log.warn("[安全更新] 参数校验失败:记录不能为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (record.getId() == null) {
|
||||
log.warn("[安全更新] 参数校验失败:记录ID不能为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("[安全更新] 开始更新拉卡拉订单记录, orderId={}, id={}",
|
||||
record.getOrder_id(), record.getId());
|
||||
|
||||
boolean result = updateById(record);
|
||||
|
||||
if (result) {
|
||||
log.info("[安全更新] 拉卡拉订单记录更新成功, orderId={}, id={}",
|
||||
record.getOrder_id(), record.getId());
|
||||
} else {
|
||||
log.warn("[安全更新] 拉卡拉订单记录更新失败, orderId={}, id={}",
|
||||
record.getOrder_id(), record.getId());
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("[安全更新] 拉卡拉订单记录更新异常, orderId={}, id={}",
|
||||
record.getOrder_id(), record.getId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -182,91 +182,73 @@ public class OssServiceImpl implements OssService {
|
||||
String ossUrl = null;
|
||||
Integer uploadType = configService.getConfig("upload", 1);
|
||||
|
||||
if (uploadType.equals(1)) {
|
||||
ossUrl = ConfigConstant.URL_BASE + "/admin/oss/upload/" + dir + "/" + uploadName; // 文件本地路径
|
||||
} else if (uploadType.equals(2)) {
|
||||
// oss 服务
|
||||
try {
|
||||
ossUrl = uploadObject2OSS(new File(uploadPath), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/").concat(uploadName), null, null, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("文件上传失败!", e);
|
||||
return null;
|
||||
}
|
||||
} else if (uploadType.equals(4)) {
|
||||
ossUrl = uploadObject4OSS(new File(uploadPath), TENGXUN_DEFAULT_DIR.concat("/").concat(dir).concat("/").concat(uploadName));
|
||||
}
|
||||
|
||||
String media_duration = "";
|
||||
try {
|
||||
if (uploadType.equals(1)) {
|
||||
ossUrl = ConfigConstant.URL_BASE + "/admin/oss/upload/" + dir + "/" + uploadName; // 文件本地路径
|
||||
} else if (uploadType.equals(2)) {
|
||||
// oss 服务
|
||||
media_duration = VideoUtil.getFormatDuration(uploadPath);
|
||||
} catch (IOException e) {
|
||||
throw new ApiException(String.format(I18nUtil._("解析音视频时长异常!url【%s】"), uploadPath));
|
||||
}
|
||||
|
||||
//截图
|
||||
//todo 放入upload中
|
||||
String thumb_file_url = "";
|
||||
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");
|
||||
|
||||
String floder = ALIYUN_OSS_DIR_PREFIX.concat("/") + dir + "/video/frame1/";
|
||||
thumb_file_url = videoUtil.getVideoCoverV2(ossUrl, floder, cover_upname);
|
||||
/*if (VideoUtil.getVideoCover(uploadPath, cover_path, 1, "375*667")) {
|
||||
try {
|
||||
ossUrl = uploadObject2OSS(new File(uploadPath), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat("/").concat(uploadName), null, null, null);
|
||||
thumb_file_url = uploadObject2OSS(new File(cover_path), ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(cover_upname), null, null, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("文件上传失败!", e);
|
||||
return null;
|
||||
}
|
||||
} else if (uploadType.equals(4)) {
|
||||
ossUrl = uploadObject4OSS(new File(uploadPath), TENGXUN_DEFAULT_DIR.concat("/").concat(dir).concat("/").concat(uploadName));
|
||||
}
|
||||
|
||||
String media_duration = "";
|
||||
try {
|
||||
media_duration = VideoUtil.getFormatDuration(uploadPath);
|
||||
} catch (IOException e) {
|
||||
throw new ApiException(String.format(I18nUtil._("解析音视频时长异常!url【%s】"), uploadPath));
|
||||
}
|
||||
|
||||
//截图
|
||||
//todo 放入upload中
|
||||
String thumb_file_url = "";
|
||||
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");
|
||||
|
||||
String floder = ALIYUN_OSS_DIR_PREFIX.concat("/") + dir + "/video/frame1/";
|
||||
try {
|
||||
thumb_file_url = videoUtil.getVideoCoverV2(ossUrl, floder, cover_upname);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取视频封面失败: ", e);
|
||||
thumb_file_url = "";
|
||||
}
|
||||
/*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(cover_upname), null, null, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
thumb_file_url = "";
|
||||
}
|
||||
} else {
|
||||
thumb_file_url = "";
|
||||
}*/
|
||||
}
|
||||
|
||||
// 保存文件信息
|
||||
MediaDTO mediaDTO = new MediaDTO();
|
||||
String name = file.getOriginalFilename();
|
||||
long size = file.getSize();
|
||||
|
||||
mediaDTO.setMedia_name(name);
|
||||
mediaDTO.setMedia_alt(name);
|
||||
mediaDTO.setMedia_size(size);
|
||||
mediaDTO.setMedia_url(ossUrl);
|
||||
mediaDTO.setMedia_order(1);
|
||||
mediaDTO.setMedia_path("/".concat(dir).concat("/").concat(uploadName));
|
||||
mediaDTO.setMedia_domain(getOssUrlPrefix().concat(ALIYUN_OSS_DIR_PREFIX));
|
||||
mediaDTO.setMedia_time(new Date());
|
||||
mediaDTO.setMedia_desc("");
|
||||
mediaDTO.setMedia_duration(media_duration);
|
||||
|
||||
shopStoreMediaService.saveMedia(mediaDTO, user);
|
||||
Map result = new HashMap<>();
|
||||
result.put("media_duration", media_duration);
|
||||
result.put("media_url", ossUrl);
|
||||
result.put("thumb", thumb_file_url);
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
// 删除临时文件
|
||||
try {
|
||||
File tempFile = new File(uploadPath);
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
logger.info("临时文件已删除: {}", uploadPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("删除临时文件失败: {}", uploadPath, e);
|
||||
}
|
||||
} else {
|
||||
thumb_file_url = "";
|
||||
}*/
|
||||
}
|
||||
|
||||
// 保存文件信息
|
||||
MediaDTO mediaDTO = new MediaDTO();
|
||||
String name = file.getOriginalFilename();
|
||||
long size = file.getSize();
|
||||
|
||||
mediaDTO.setMedia_name(name);
|
||||
mediaDTO.setMedia_alt(name);
|
||||
mediaDTO.setMedia_size(size);
|
||||
mediaDTO.setMedia_url(ossUrl);
|
||||
mediaDTO.setMedia_order(1);
|
||||
mediaDTO.setMedia_path("/".concat(dir).concat("/").concat(fileName));
|
||||
mediaDTO.setMedia_domain(getOssUrlPrefix().concat(ALIYUN_OSS_DIR_PREFIX));
|
||||
mediaDTO.setMedia_time(new Date());
|
||||
mediaDTO.setMedia_desc("");
|
||||
mediaDTO.setMedia_duration(media_duration);
|
||||
|
||||
shopStoreMediaService.saveMedia(mediaDTO, user);
|
||||
Map result = new HashMap<>();
|
||||
result.put("media_duration", media_duration);
|
||||
result.put("media_url", ossUrl);
|
||||
result.put("thumb", thumb_file_url);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map upload(MultipartFile file, UserDto user) {
|
||||
@ -598,7 +580,7 @@ public class OssServiceImpl implements OssService {
|
||||
ObjectListing objectListing = ossCli.listObjects(listObjectsRequest);
|
||||
List<String> commonPrefixes = objectListing.getCommonPrefixes();
|
||||
logger.info(JSONUtil.toJsonStr(commonPrefixes));
|
||||
return commonPrefixes;
|
||||
return commonPrefixes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -650,7 +632,8 @@ public class OssServiceImpl implements OssService {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ossFolder 如folder/example.txt
|
||||
*
|
||||
* @param ossFolder 如folder/example.txt
|
||||
* @param localFolder 如/path/to/local/example.txt
|
||||
* @return
|
||||
*/
|
||||
|
||||
@ -16,7 +16,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -25,7 +24,14 @@ import java.util.concurrent.TimeUnit;
|
||||
@Component
|
||||
public class VideoUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(VideoUtil.class);
|
||||
private static Logger logger = LoggerFactory.getLogger(VideoUtil.class);
|
||||
|
||||
@Value("${aliyun.oss.dir.prefix}")
|
||||
private String ALIYUN_OSS_DIR_PREFIX;
|
||||
|
||||
@Autowired
|
||||
private OssService ossService;
|
||||
|
||||
public static List<String> videoAllowFiles = new ArrayList<String>() {{
|
||||
add("flv");
|
||||
add("swf");
|
||||
@ -45,10 +51,6 @@ public class VideoUtil {
|
||||
// add("wav");
|
||||
// add("mid");
|
||||
}};
|
||||
@Value("${aliyun.oss.dir.prefix}")
|
||||
private String ALIYUN_OSS_DIR_PREFIX;
|
||||
@Autowired
|
||||
private OssService ossService;
|
||||
|
||||
/**
|
||||
* 得到语音或视频文件时长,单位秒 并格式化
|
||||
@ -211,7 +213,8 @@ public class VideoUtil {
|
||||
int mm = (temp % 3600) / 60;
|
||||
int ss = (temp % 3600) % 60;
|
||||
|
||||
return hh != 0 ? ((hh < 10 ? ("0" + hh) : hh) + ":") : (mm < 10 ? ("0" + mm) : mm) + ":" +
|
||||
return hh != 0 ? ((hh < 10 ? ("0" + hh) : hh) + ":") : "" +
|
||||
(mm < 10 ? ("0" + mm) : mm) + ":" +
|
||||
(ss < 10 ? ("0" + ss) : ss);
|
||||
}
|
||||
|
||||
@ -224,40 +227,24 @@ public class VideoUtil {
|
||||
* @return
|
||||
*/
|
||||
public String getVideoCoverV2(String video, String dir, String uploadName) {
|
||||
InputStream inputStream = OssUtils.urlToInputSteam(video);
|
||||
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
|
||||
try {
|
||||
InputStream inputStream = OssUtils.urlToInputSteam(video);
|
||||
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
|
||||
try {
|
||||
grabber.start();
|
||||
Frame frame = grabber.grabImage();
|
||||
Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||
BufferedImage bufferedImage = converter.convert(frame);
|
||||
Map map = OssUtils.toStreamMap(bufferedImage);
|
||||
grabber.stop();
|
||||
InputStream stream = (InputStream) map.get("stream");
|
||||
Long file_size = Convert.toLong(map.get("file_size"));
|
||||
grabber.start();
|
||||
Frame frame = grabber.grabImage();
|
||||
Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||
BufferedImage bufferedImage = converter.convert(frame);
|
||||
Map map = OssUtils.toStreamMap(bufferedImage);
|
||||
grabber.stop();
|
||||
InputStream stream = (InputStream) map.get("stream");
|
||||
Long file_size = Convert.toLong(map.get("file_size"));
|
||||
|
||||
// 上传至oos,返回文件地址
|
||||
return ossService.uploadObject2OSS(null, ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(uploadName), stream, uploadName, file_size);
|
||||
} catch (IOException e) {
|
||||
logger.error("处理视频封面失败:", e);
|
||||
} finally {
|
||||
try {
|
||||
if (grabber != null) {
|
||||
grabber.stop();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("关闭视频抓取器失败:", e);
|
||||
}
|
||||
}
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
logger.error("JavaCV本地库加载失败,请检查平台依赖配置:", e);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
logger.error("JavaCV类初始化失败,请检查依赖配置:", e);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取视频封面时发生未知异常:", e);
|
||||
// 上传至oos,返回文件地址
|
||||
return ossService.uploadObject2OSS(null, ALIYUN_OSS_DIR_PREFIX.concat("/").concat(dir).concat(uploadName), stream, uploadName, file_size);
|
||||
} catch (IOException e) {
|
||||
logger.error("失败原因:", e);
|
||||
}
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -268,7 +255,7 @@ class InputStreamRunnable extends Thread {
|
||||
|
||||
public InputStreamRunnable(InputStream is, String _type) {
|
||||
try {
|
||||
bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), StandardCharsets.UTF_8));
|
||||
bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), "UTF-8"));
|
||||
type = _type;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@ -59,7 +59,6 @@ import com.suisung.mall.shop.store.service.*;
|
||||
import com.suisung.mall.shop.user.service.ShopUserFavoritesItemService;
|
||||
import com.suisung.mall.shop.user.service.ShopUserProductBrowseService;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -91,7 +90,6 @@ import static com.suisung.mall.common.utils.I18nUtil._;
|
||||
* @author Xinze
|
||||
* @since 2021-04-07
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ShopProductItemServiceImpl extends BaseServiceImpl<ShopProductItemMapper, ShopProductItem> implements ShopProductItemService {
|
||||
|
||||
@ -2239,34 +2237,17 @@ public class ShopProductItemServiceImpl extends BaseServiceImpl<ShopProductItemM
|
||||
}
|
||||
|
||||
/**
|
||||
* 锁定SKU库存
|
||||
* 锁定库存
|
||||
*
|
||||
* @param itemId 商品SKU ID
|
||||
* @param cartQuantity 购物车商品数量
|
||||
* @return 影响的行数,1表示锁定成功,0表示锁定失败(库存不足)
|
||||
* @param itemId
|
||||
* @param cart_quantity
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int lockSkuStock(Long itemId, int cartQuantity) {
|
||||
// 参数校验
|
||||
if (itemId == null || cartQuantity <= 0) {
|
||||
log.warn("锁定SKU库存参数异常: itemId={}, cartQuantity={}", itemId, cartQuantity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 调用Mapper方法锁定库存
|
||||
int affectedRows = this.baseMapper.lockSkuStock(itemId, cartQuantity);
|
||||
|
||||
// 清理SKU库存缓存
|
||||
public int lockSkuStock(Long itemId, int cart_quantity) {
|
||||
int flag = this.baseMapper.lockSkuStock(itemId, cart_quantity);
|
||||
cleanSkuStockCache(itemId);
|
||||
|
||||
// 记录库存锁定操作日志
|
||||
if (affectedRows > 0) {
|
||||
log.debug("SKU库存锁定成功: itemId={}, cartQuantity={}, affectedRows={}", itemId, cartQuantity, affectedRows);
|
||||
} else {
|
||||
log.warn("SKU库存锁定失败,可能库存不足: itemId={}, cartQuantity={}", itemId, cartQuantity);
|
||||
}
|
||||
|
||||
return affectedRows;
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -118,7 +118,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
|
||||
ShopMchEntry shopMchEntry;
|
||||
if (ObjectUtil.isEmpty(mchId)) {
|
||||
shopMchEntry = shopMchEntryService.getShopMerchEntryByStoreId(storeId);
|
||||
shopMchEntry = shopMchEntryService.shopMerchEntryByStoreId(storeId);
|
||||
} else {
|
||||
shopMchEntry = shopMchEntryService.shopMerchEntryById(mchId);
|
||||
}
|
||||
@ -488,7 +488,6 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
ShopStoreSfOrder shopStoreSfOrder = JSONUtil.toBean(sfExpressApiRes.get("result").toString(), ShopStoreSfOrder.class);
|
||||
shopStoreSfOrder.setDev_id(sfCreateOrderReq.getDev_id());
|
||||
shopStoreSfOrder.setOrder_status(SFExpressConstant.Cons_CreatedOrder);
|
||||
shopStoreSfOrder.setShop_id(sfCreateOrderReq.getShop_id());
|
||||
shopStoreSfOrder.setStatus_desc("已创建顺丰同城订单");
|
||||
|
||||
// 下单成功,保存顺丰同城订单记录到 shop_store_sf_order 表里
|
||||
@ -809,98 +808,66 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
|
||||
/**
|
||||
* 接收顺丰原因订单取消回调
|
||||
* <p>
|
||||
* 该方法用于处理顺丰同城配送订单取消的回调通知。当顺丰因为某种原因取消订单时,
|
||||
* 会调用此接口通知商城系统,商城系统需要更新订单状态为已取消,并执行相关业务逻辑。
|
||||
* </p>
|
||||
*
|
||||
* @param jsonData 包含订单取消信息的JSON数据
|
||||
* @param sign 请求签名,用于验证请求的合法性
|
||||
* @return ThirdApiRes 处理结果响应对象
|
||||
* <ul>
|
||||
* <li>成功: {"error_code": 0, "reason": "success"}</li>
|
||||
* <li>失败: {"error_code": 错误码, "reason": "错误信息"}</li>
|
||||
* </ul>
|
||||
* @param jsonData
|
||||
* @param sign
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ThirdApiRes receiveCancelOrderNotify(String jsonData, String sign) {
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(jsonData) || StrUtil.isBlank(sign)) {
|
||||
logger.warn("[顺丰订单取消回调通知] 缺少必要参数: jsonData或sign为空");
|
||||
return new ThirdApiRes().fail(1003, "缺少必要参数!");
|
||||
}
|
||||
|
||||
// 签名校验
|
||||
if (!checkOpenSign(sign, jsonData)) {
|
||||
logger.warn("[顺丰订单取消回调通知] 请求签名sign校验失败");
|
||||
return new ThirdApiRes().fail(2002, "请求签名sign校验失败!");
|
||||
}
|
||||
|
||||
logger.info("[顺丰订单取消回调通知] 接收回调数据: {}", jsonData);
|
||||
logger.info("接收顺丰原因订单取消回调返回的 JSON 数据:{}", jsonData);
|
||||
|
||||
try {
|
||||
// 解析并更新顺丰同城订单状态
|
||||
ShopStoreSfOrder shopStoreSfOrder = toShopStoreSfOrder(jsonData);
|
||||
if (shopStoreSfOrder == null) {
|
||||
logger.error("[顺丰订单取消回调通知] 解析订单数据失败: jsonData={}", jsonData);
|
||||
return new ThirdApiRes().fail(-1, "订单数据解析失败!");
|
||||
}
|
||||
// 更改顺丰同城订单状态
|
||||
ShopStoreSfOrder shopStoreSfOrder = toShopStoreSfOrder(jsonData);
|
||||
|
||||
String shopOrderId = shopStoreSfOrder.getShop_order_id();
|
||||
String sfOrderId = shopStoreSfOrder.getSf_order_id();
|
||||
|
||||
logger.info("[顺丰订单取消回调通知] 处理订单取消: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
|
||||
|
||||
// 判断订单的状态,是否已经取消了?已取消,不再执行
|
||||
ShopStoreSfOrder shopStoreSfOrderExist = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
|
||||
if (shopStoreSfOrderExist != null && shopStoreSfOrderExist.getOrder_status() != null
|
||||
&& (ObjectUtil.equal(shopStoreSfOrderExist.getOrder_status(), StateCode.SF_ORDER_STATUS_CANCELED) ||
|
||||
ObjectUtil.equal(shopStoreSfOrderExist.getOrder_status(), StateCode.SF_ORDER_STATUS_CANCELING))) {
|
||||
logger.info("[顺丰订单取消回调通知] 订单已处于取消状态,无需重复处理: sfOrderId={} status={}",
|
||||
sfOrderId, shopStoreSfOrderExist.getOrder_status());
|
||||
return new ThirdApiRes().success("success");
|
||||
}
|
||||
|
||||
// 更新顺丰订单状态
|
||||
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
|
||||
if (!success) {
|
||||
logger.error("[顺丰订单取消回调通知] 更新顺丰订单状态失败: sfOrderId={}", sfOrderId);
|
||||
return new ThirdApiRes().fail(-1, "状态处理失败!");
|
||||
}
|
||||
logger.debug("[顺丰订单取消回调通知] 顺丰订单状态更新成功: sfOrderId={}", sfOrderId);
|
||||
|
||||
// 重要:更改商城订单状态为:已取消,注意事务问题
|
||||
success = shopOrderReturnService.sfExpressExpiredForceRefund(shopOrderId);
|
||||
if (!success) {
|
||||
logger.error("[顺丰订单取消回调通知] 取消商城订单业务处理失败: shopOrderId={}", shopOrderId);
|
||||
return new ThirdApiRes().fail(-1, "取消订单业务处理失败!");
|
||||
}
|
||||
logger.debug("[顺丰订单取消回调通知] 商城订单取消处理成功: shopOrderId={}", shopOrderId);
|
||||
|
||||
// 获取顺丰同城的物流轨迹
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("order_id", sfOrderId);
|
||||
ThirdApiRes feedRes = listOrderFeed(params);
|
||||
if (feedRes != null && ObjectUtil.equal(feedRes.getError_code(), 0)) {
|
||||
JSONObject result = JSONUtil.parseObj(feedRes.getResult());
|
||||
if (result != null && result.get("feed") != null) {
|
||||
shopStoreSfOrder.setFeed(JSONUtil.toJsonStr(result.get("feed")));
|
||||
logger.debug("[顺丰订单取消回调通知] 获取物流轨迹成功: sfOrderId={}", sfOrderId);
|
||||
}
|
||||
}
|
||||
|
||||
// 个推推送消息
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ORDER_DETAIL);
|
||||
payload.put("orderId", shopOrderId);
|
||||
pushMessageService.noticeMerchantEmployeeOrderAction(null, shopOrderId, "您有一笔取消订单", "您有一笔取消订单[" + shopOrderId + "],请及时处理。", payload);
|
||||
|
||||
logger.info("[顺丰订单取消回调通知] 处理完成: shopOrderId={} sfOrderId={}", shopOrderId, sfOrderId);
|
||||
String shopOrderId = shopStoreSfOrder.getShop_order_id();
|
||||
String sfOrderId = shopStoreSfOrder.getSf_order_id();
|
||||
// 判断订单的状态,是否已经取消了?已取消,不再执行
|
||||
ShopStoreSfOrder shopStoreSfOrderExist = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
|
||||
if (shopStoreSfOrderExist != null && shopStoreSfOrderExist.getOrder_status() != null
|
||||
&& (shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELED) ||
|
||||
(shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELING)))) {
|
||||
return new ThirdApiRes().success("success");
|
||||
} catch (Exception e) {
|
||||
logger.error("[顺丰订单取消回调通知] 处理过程中发生异常", e);
|
||||
return new ThirdApiRes().fail(-1, "系统处理异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
|
||||
if (!success) {
|
||||
return new ThirdApiRes().fail(-1, "状态处理失败!");
|
||||
}
|
||||
|
||||
// 重要:更改商城订单状态为:已取消,注意事务问题
|
||||
success = shopOrderReturnService.sfExpressExpiredForceRefund(shopOrderId);
|
||||
if (!success) {
|
||||
return new ThirdApiRes().fail(-1, "取消订单业务处理失败!");
|
||||
}
|
||||
|
||||
// 获取顺丰同城的物流轨迹
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("order_id", sfOrderId);
|
||||
ThirdApiRes feedRes = listOrderFeed(params);
|
||||
if (feedRes != null && feedRes.getError_code().equals(0)) {
|
||||
JSONObject result = JSONUtil.parseObj(feedRes.getResult());
|
||||
if (result != null && result.get("feed") != null) {
|
||||
shopStoreSfOrder.setFeed(JSONUtil.toJsonStr(result.get("feed")));
|
||||
}
|
||||
}
|
||||
|
||||
// 个推推送消息
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("category", CommonConstant.PUSH_MSG_CATE_MCH_ORDER_DETAIL);
|
||||
payload.put("orderId", shopOrderId);
|
||||
pushMessageService.noticeMerchantEmployeeOrderAction(null, shopOrderId, "您有一笔取消订单", "您有一笔取消订单[" + shopOrderId + "],请及时处理。", null);
|
||||
|
||||
|
||||
return new ThirdApiRes().success("success");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -968,7 +935,8 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
pushRemark = "配送员已接单。";
|
||||
|
||||
// 上传发货信息到微信
|
||||
wxOrderShippingService.uploadShippingInfoToWx(2, shopOrderId);
|
||||
wxOrderShippingService.uploadShippingInfoToWx(2, shopStoreSfOrder.getShop_order_id());
|
||||
|
||||
} else if (shopStoreSfOrder.getOrder_status().equals(StateCode.SF_ORDER_STATUS_ARRIVED)) {
|
||||
// 顺丰同城状态:12-配送员到店;
|
||||
// 商城订单状态:从 2020-待配货 到 2030; //待发货
|
||||
@ -978,7 +946,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
pushRemark = "配送员已到店。";
|
||||
|
||||
// 上传发货信息到微信
|
||||
wxOrderShippingService.uploadShippingInfoToWx(2, shopOrderId);
|
||||
wxOrderShippingService.uploadShippingInfoToWx(2, shopStoreSfOrder.getShop_order_id());
|
||||
} else if (shopStoreSfOrder.getOrder_status().equals(StateCode.SF_ORDER_STATUS_RECEIVED)) {
|
||||
// 顺丰同城状态:15-配送员配送中(已取货)
|
||||
// 商城订单状态:从 2030-待发货 到 2040-已发货/待收货确认
|
||||
@ -986,26 +954,26 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
orderIsOutStatus = 0;
|
||||
orderIsShippedStatus = StateCode.ORDER_SHIPPED_STATE_YES; // 已发货
|
||||
pushRemark = "配送员已取货。";
|
||||
// 上传发货信息到微信
|
||||
wxOrderShippingService.uploadShippingInfoToWx(2, shopOrderId);
|
||||
} else if (shopStoreSfOrder.getOrder_status().equals(StateCode.SF_ORDER_STATUS_FINISH)) {
|
||||
// 顺丰同城状态:17-配送员妥投完单;
|
||||
// orderStatus = StateCode.ORDER_STATE_FINISH;
|
||||
pushRemark = "已完成配送";
|
||||
orderStatus = StateCode.ORDER_STATE_RECEIVED; //已签收
|
||||
|
||||
// 通知微信用户确认收货(同城配送不能调用微信的确认收货)
|
||||
// wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());
|
||||
// 不要提前 订单确认收货,等微信拉卡拉确认通知
|
||||
// try {
|
||||
// shopOrderBaseService.receive(shopOrderId, null);
|
||||
// } catch (Exception e) {
|
||||
// logger.error("订单确认收货失败!", e);
|
||||
// }
|
||||
// 订单确认收货
|
||||
shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
|
||||
}
|
||||
|
||||
shopOrderInfoService.changeOrderStatus(shopOrderId, orderStatus, orderIsOutStatus, orderIsShippedStatus);
|
||||
success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), orderStatus, orderIsOutStatus, orderIsShippedStatus);
|
||||
if (!success) {
|
||||
throw new ApiException(I18nUtil._("状态处理失败!"));
|
||||
}
|
||||
|
||||
// 注:状态更改之后,给 SSE 监听服务发送更改的数据
|
||||
// logger.debug("准备发送SSE消息...");
|
||||
// SseEmitterUtil.sendMessage(shopStoreSfOrder.getSf_order_id(), jsonData);
|
||||
// logger.debug("向 SSE 通道 {} 发送了:{}", shopStoreSfOrder.getSf_order_id(), jsonData);
|
||||
|
||||
// 消息推送
|
||||
JSONObject payload = new JSONObject();
|
||||
@ -1042,9 +1010,9 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
return new ThirdApiRes().fail(-1, "返回数据转换失败!");
|
||||
}
|
||||
|
||||
String orderId = shopStoreSfOrder.getShop_order_id();
|
||||
|
||||
String sfOrderId = shopStoreSfOrder.getSf_order_id();
|
||||
ShopStoreSfOrder order = shopStoreSfOrderService.getBySfOrderId(sfOrderId);
|
||||
ShopStoreSfOrder order = shopStoreSfOrderService.getBySfOrderId(orderId);
|
||||
if (order == null) {
|
||||
return new ThirdApiRes().fail(-1, "订单不存在!");
|
||||
}
|
||||
@ -1082,20 +1050,21 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
|
||||
// 更改商城订单状态为:已完成,注意事务问题
|
||||
// 配送员已取单配送中
|
||||
// 商城订单状态:从 040-已发货/待收货确认 到 2060-已完成/已签收 (RMK 这里可能有点问题,需要等待用户确认收货,才能设置订单已完成)
|
||||
// success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), StateCode.ORDER_STATE_FINISH, 0, 0);
|
||||
success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), StateCode.ORDER_STATE_RECEIVED, 0, 0);
|
||||
// 商城订单状态:从 040-已发货/待收货确认 到 2060-已完成/已签收
|
||||
success = shopOrderInfoService.changeOrderStatus(shopStoreSfOrder.getShop_order_id(), StateCode.ORDER_STATE_FINISH, 0, 0);
|
||||
if (!success) {
|
||||
throw new ApiException(I18nUtil._("状态处理失败!"));
|
||||
}
|
||||
|
||||
// 注:状态更改之后,给 SSE 监听服务发送更改的数据
|
||||
// logger.debug("准备发送SSE消息...");
|
||||
// SseEmitterUtil.sendMessage(shopStoreSfOrder.getSf_order_id(), jsonData);
|
||||
|
||||
// 通知微信用户确认收货(同城配送不能调用该微信接口)
|
||||
// wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());
|
||||
|
||||
// 订单确认收货
|
||||
// shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
|
||||
String orderId = shopStoreSfOrder.getShop_order_id();
|
||||
shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
|
||||
// 消息推送
|
||||
JSONObject payload = new JSONObject();
|
||||
|
||||
@ -73,7 +73,7 @@ public class StoreController extends BaseControllerImpl {
|
||||
@RequestMapping(value = "/lists", method = RequestMethod.GET)
|
||||
public CommonResult lists(@RequestParam(name = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(name = "rows", defaultValue = "10") Integer rows) {
|
||||
return CommonResult.success(shopStoreBaseService.getStoreList(page, rows, new HashMap<>()));
|
||||
return CommonResult.success(shopStoreBaseService.getStoreList(page, rows,new HashMap<>()));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "列出店铺分类", notes = "列出店铺分类")
|
||||
@ -314,4 +314,26 @@ public class StoreController extends BaseControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 列表查询
|
||||
// * @return
|
||||
// */
|
||||
// @ApiOperation(value = "店铺分类表-分类强调区别, 类型强调共性-分页列表查询", notes = "店铺分类表-分类强调区别, 类型强调共性-分页列表查询")
|
||||
// @RequestMapping(value = "/categoryTree", method = RequestMethod.GET)
|
||||
// public CommonResult categoryTree(ShopBaseStoreCategory category) {
|
||||
// QueryWrapper<ShopBaseStoreCategory> queryWrapper = new QueryWrapper<>();
|
||||
// if (category.getStore_category_parent_id() != null)
|
||||
// queryWrapper.eq("store_category_parent_id", category.getStore_category_parent_id());
|
||||
//
|
||||
// return CommonResult.success(shopBaseStoreCategoryService.getMobileCategoryTree(queryWrapper));
|
||||
// }
|
||||
|
||||
// @ApiOperation(value = "根据分类查询店铺", notes = "列表数据")
|
||||
// @RequestMapping(value = "/listStores", method = RequestMethod.GET)
|
||||
// public Page<ShopStoreBase> listStores(@RequestParam(name = "page", defaultValue = "1") Integer page,
|
||||
// @RequestParam(name = "rows", defaultValue = "10") Integer rows) {
|
||||
// return shopStoreBaseService.getMobileStoreList(page, rows);
|
||||
// }
|
||||
|
||||
}
|
||||
@ -13,7 +13,6 @@ import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.modules.store.ShopMchEntry;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public interface ShopMchEntryService {
|
||||
@ -115,7 +114,7 @@ public interface ShopMchEntryService {
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
ShopMchEntry getShopMerchEntryByStoreId(Integer storeId);
|
||||
ShopMchEntry shopMerchEntryByStoreId(Integer storeId);
|
||||
|
||||
|
||||
/**
|
||||
@ -215,7 +214,7 @@ public interface ShopMchEntryService {
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
Boolean updateMerchEntryStoreStatus(Long id, Integer storeId);
|
||||
Boolean updateMerchEntryStoreId(Long id, Integer storeId);
|
||||
|
||||
/**
|
||||
* 更新商户入驻信息的拉卡拉电子合同相关信息
|
||||
@ -228,7 +227,7 @@ public interface ShopMchEntryService {
|
||||
* @param lklElectronicContractFilePath 拉卡拉电子合同文件路径
|
||||
* @return 更新成功返回 true, 失败返回 false
|
||||
*/
|
||||
Boolean updateMerchantLklEContractInfo(Long merchantId, String lklElectronicContractNo, String lklElectronicContractName, String lklElectronicContractResultUrl, String contractDownloadUrl, String lklElectronicContractFilePath);
|
||||
Boolean updateMerchantLklElectronicContractInfo(Long merchantId, String lklElectronicContractNo, String lklElectronicContractName, String lklElectronicContractResultUrl, String contractDownloadUrl, String lklElectronicContractFilePath);
|
||||
|
||||
/**
|
||||
* 更新商家入驻申请的审批状态和审批备注
|
||||
@ -335,17 +334,4 @@ public interface ShopMchEntryService {
|
||||
* @return boolean 是否成功修复至少一个商户信息
|
||||
*/
|
||||
Boolean checkAndFixMchStoreInfo(String loginMobile);
|
||||
|
||||
/**
|
||||
* 获取商户入驻分账比例
|
||||
* <p>
|
||||
* 该分账比例是实际的分账百分比,最终提交给拉卡拉的合同的分账比例是 20%。
|
||||
*
|
||||
* @param mch1stBizCategory 商户一级业务分类
|
||||
* @param mch2ndBizCategory 商户二级业务分类
|
||||
* @param srcRatio 源比例
|
||||
* @param defaultRatio 无值的时候默认比例
|
||||
* @return 分账比例
|
||||
*/
|
||||
BigDecimal getMchEntryRatioOrDefault(Integer mch1stBizCategory, Integer mch2ndBizCategory, BigDecimal srcRatio, BigDecimal defaultRatio);
|
||||
}
|
||||
@ -17,14 +17,6 @@ import java.util.Map;
|
||||
*/
|
||||
public interface ShopStoreAnalyticsService extends IBaseService<ShopStoreAnalytics> {
|
||||
|
||||
/**
|
||||
* 根据店铺id查询店铺统计信息
|
||||
*
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
ShopStoreAnalytics getByStoreId(Integer storeId);
|
||||
|
||||
List<Map> getAnalytics(List<Integer> store_id);
|
||||
|
||||
boolean saveProductAnalyticsNum(Integer store_id);
|
||||
|
||||
@ -14,13 +14,5 @@ import com.suisung.mall.core.web.service.IBaseService;
|
||||
*/
|
||||
public interface ShopStoreCompanyService extends IBaseService<ShopStoreCompany> {
|
||||
|
||||
/**
|
||||
* 获取店铺公司信息
|
||||
*
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
ShopStoreCompany getCompany(Integer storeId);
|
||||
|
||||
boolean saveOrUpdateCompany(ShopStoreCompany shopStoreCompany);
|
||||
}
|
||||
|
||||
@ -38,17 +38,6 @@ public interface ShopStoreEmployeeService extends IBaseService<ShopStoreEmployee
|
||||
*/
|
||||
List<Integer> selectEmployeeByStoreId(Integer storeId, String rightsGroupName);
|
||||
|
||||
/**
|
||||
* 根据店铺Id和员工Id获取员工信息
|
||||
*
|
||||
* @param storeId
|
||||
* @param userId
|
||||
* @param isAdmin
|
||||
* @return
|
||||
*/
|
||||
List<ShopStoreEmployee> selectEmployeeByCondition(Integer storeId, Integer userId, Boolean isAdmin);
|
||||
|
||||
|
||||
/**
|
||||
* 根据店铺Id获取店铺的所有员工的个推 CID 列表
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -35,22 +35,6 @@ public class ShopStoreAnalyticsServiceImpl extends BaseServiceImpl<ShopStoreAnal
|
||||
@Autowired
|
||||
private ShopProductBaseService shopProductBaseService;
|
||||
|
||||
/**
|
||||
* 根据店铺id查询店铺统计信息
|
||||
*
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ShopStoreAnalytics getByStoreId(Integer storeId) {
|
||||
try {
|
||||
return getById(storeId);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键值,从数据库读取数据, 必须获取主键后再读取数据
|
||||
*
|
||||
@ -119,24 +103,15 @@ public class ShopStoreAnalyticsServiceImpl extends BaseServiceImpl<ShopStoreAnal
|
||||
@Override
|
||||
public boolean saveProductAnalyticsNum(Integer store_id) {
|
||||
|
||||
ShopStoreAnalytics analytics = new ShopStoreAnalytics();
|
||||
long store_product_new_num = shopProductBaseService.getProductNum(StateCode.PRODUCT_STATE_NORMAL, store_id, -30, null);
|
||||
long store_product_num = shopProductBaseService.getProductNum(StateCode.PRODUCT_STATE_NORMAL, store_id, null, null);
|
||||
|
||||
ShopStoreAnalytics analytics = new ShopStoreAnalytics();
|
||||
analytics.setStore_id(store_id);
|
||||
analytics.setStore_product_new_num(store_product_new_num);
|
||||
analytics.setStore_product_num(store_product_num);
|
||||
|
||||
// 先尝试查询是否存在记录
|
||||
ShopStoreAnalytics existingAnalytics = getById(store_id);
|
||||
|
||||
if (existingAnalytics != null) {
|
||||
// 如果记录存在,使用updateById更新
|
||||
return updateById(analytics);
|
||||
} else {
|
||||
// 如果记录不存在,使用insert插入
|
||||
return save(analytics);
|
||||
}
|
||||
return saveOrUpdate(analytics);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2033,7 +2033,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
// 添加默认客户等级
|
||||
InvoicingCustomerLevel invoicingCustomerLevel = new InvoicingCustomerLevel();
|
||||
invoicingCustomerLevel.setCustomer_level_name(I18nUtil._("普通(系统默认,不可删除)"));
|
||||
invoicingCustomerLevel.setCustomer_level_discountrate(new BigDecimal(100));
|
||||
invoicingCustomerLevel.setCustomer_level_discountrate(new BigDecimal("100"));
|
||||
invoicingCustomerLevel.setCustomer_level_is_buildin(1);
|
||||
invoicingCustomerLevel.setCustomer_level_desc("");
|
||||
|
||||
@ -2375,7 +2375,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
// 打包费
|
||||
BigDecimal packingFee = Convert.toBigDecimal(getParameter("packing_fee"));
|
||||
if (packingFee == null || packingFee.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
packingFee = BigDecimal.ZERO;
|
||||
base.setPacking_fee(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
if (packingFee.compareTo(new BigDecimal("10")) > 0) {
|
||||
@ -2383,13 +2383,6 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
}
|
||||
base.setPacking_fee(packingFee);
|
||||
|
||||
Integer ringtoneIsEnable = Convert.toInt(getParameter("ringtone_is_enable"));
|
||||
if (ringtoneIsEnable == null || ringtoneIsEnable <= 0) {
|
||||
ringtoneIsEnable = CommonConstant.Enable;
|
||||
}
|
||||
|
||||
base.setRingtone_is_enable(ringtoneIsEnable);
|
||||
|
||||
|
||||
// 百度坐标系BD09经纬度 转出 火星坐标系GCJ02经纬度 (因为数据库保存的经纬度统一是GCJ02经纬度,所以需要转换 )
|
||||
base = bd09ToGcj02Gps(base);
|
||||
@ -2545,7 +2538,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
// 打包费
|
||||
BigDecimal packingFee = Convert.toBigDecimal(getParameter("packing_fee"));
|
||||
if (packingFee == null || packingFee.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
packingFee = BigDecimal.ZERO;
|
||||
base.setPacking_fee(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
if (packingFee.compareTo(new BigDecimal("10")) > 0) {
|
||||
@ -2553,13 +2546,6 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
}
|
||||
base.setPacking_fee(packingFee);
|
||||
|
||||
Integer ringtoneIsEnable = Convert.toInt(getParameter("ringtone_is_enable"));
|
||||
if (ringtoneIsEnable == null || ringtoneIsEnable <= 0) {
|
||||
ringtoneIsEnable = CommonConstant.Enable;
|
||||
}
|
||||
|
||||
base.setRingtone_is_enable(ringtoneIsEnable);
|
||||
|
||||
// 百度坐标系BD09经纬度 转出 火星坐标系GCJ02经纬度 (因为数据库保存的经纬度统一是GCJ02经纬度,所以需要转换 )
|
||||
base = bd09ToGcj02Gps(base);
|
||||
|
||||
@ -2748,14 +2734,6 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
if (CheckUtil.isNotEmpty(store_id)) {
|
||||
|
||||
ShopStoreBase shopStoreBase = get(store_id);
|
||||
if (shopStoreBase == null) {
|
||||
throw new ApiException("无法找到店铺信息!");
|
||||
}
|
||||
|
||||
if (CheckUtil.isEmpty(shopStoreBase.getRingtone_is_enable())) {
|
||||
shopStoreBase.setRingtone_is_enable(CommonConstant.Enable);
|
||||
}
|
||||
|
||||
row = Convert.toMap(Object.class, Object.class, shopStoreBase);
|
||||
ShopStoreInfo shopStoreInfo = shopStoreInfoService.get(store_id);
|
||||
if (shopStoreInfo != null) {
|
||||
@ -3068,17 +3046,17 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
params.put("countyId", countyId);
|
||||
params.put("userLng", userLng);
|
||||
params.put("userLat", userLat);
|
||||
List<Integer> storeCategoryIds = new ArrayList<>();
|
||||
List<Integer> storeCategoryIds=new ArrayList<>();
|
||||
QueryWrapper<ShopBaseStoreCategory> storeCategoryQueryWrapper = new QueryWrapper<>();
|
||||
storeCategoryQueryWrapper.eq("store_category_parent_id", storeCategoryId);
|
||||
List<ShopBaseStoreCategory> shopBaseStoreCategories = shopBaseStoreCategoryService.list(storeCategoryQueryWrapper);
|
||||
if (!shopBaseStoreCategories.isEmpty()) {
|
||||
storeCategoryQueryWrapper.eq("store_category_parent_id",storeCategoryId);
|
||||
List<ShopBaseStoreCategory> shopBaseStoreCategories= shopBaseStoreCategoryService.list(storeCategoryQueryWrapper);
|
||||
if(!shopBaseStoreCategories.isEmpty()){
|
||||
storeCategoryIds.add(storeCategoryId);
|
||||
shopBaseStoreCategories.forEach(shopBaseStoreCategory -> {
|
||||
storeCategoryIds.add(shopBaseStoreCategory.getStore_category_id());
|
||||
});
|
||||
params.put("storeCategoryIds", storeCategoryIds);
|
||||
} else {
|
||||
}else {
|
||||
params.put("storeCategoryId", storeCategoryId);
|
||||
}
|
||||
|
||||
@ -3187,12 +3165,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
shopStoreBase.setUser_id(userId); // 店铺管理员用户Id
|
||||
shopStoreBase.setStore_name(shopMchEntry.getStore_name());
|
||||
shopStoreBase.setStore_category_id(shopMchEntry.getBiz_category()); // 重要,店铺分类id,对应 shop_base_store_category 表的分类
|
||||
shopStoreBase.setStore_2nd_category_id(shopMchEntry.getBiz_second_category());
|
||||
|
||||
// 分账比例,最终提交给拉卡拉的分账比例是 20%。
|
||||
BigDecimal splitRatio = shopMchEntryService.getMchEntryRatioOrDefault(shopMchEntry.getBiz_category(), shopMchEntry.getBiz_second_category(), shopMchEntry.getSplit_ratio(), new BigDecimal(94));
|
||||
|
||||
shopStoreBase.setSplit_ratio(splitRatio); // 分账比例
|
||||
shopStoreBase.setSplit_ratio(shopMchEntry.getSplit_ratio()); // 分账比例
|
||||
shopStoreBase.setPacking_fee(BigDecimal.ZERO);// 默认0元打包费
|
||||
String storeFacadeImage = shopMchEntry.getFront_facade_image();
|
||||
String storeLogoImage = shopMchEntry.getStore_logo();
|
||||
@ -3280,83 +3253,73 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
|
||||
// 初始化默认公司信息,避免商家编辑不了,申请入驻即使是个人类型的,也需要保存相关应有信息,公司信息不能空着
|
||||
// shop_store_company
|
||||
ShopStoreCompany shopStoreCompany = shopStoreCompanyService.getCompany(storeId);
|
||||
if (shopStoreCompany == null) {
|
||||
shopStoreCompany.setUser_id(userId);
|
||||
shopStoreCompany.setStore_id(storeId);
|
||||
ShopStoreCompany shopStoreCompany = new ShopStoreCompany();
|
||||
shopStoreCompany.setUser_id(userId);
|
||||
shopStoreCompany.setStore_id(storeId);
|
||||
|
||||
// 联系人
|
||||
shopStoreCompany.setContacts_name(shopMchEntry.getContact_name());
|
||||
shopStoreCompany.setContacts_phone(contact_mobile);
|
||||
// 联系人
|
||||
shopStoreCompany.setContacts_name(shopMchEntry.getContact_name());
|
||||
shopStoreCompany.setContacts_phone(contact_mobile);
|
||||
|
||||
// 公司名
|
||||
String companyName = StrUtil.isBlank(shopMchEntry.getBiz_license_company()) ? shopMchEntry.getStore_name() : shopMchEntry.getBiz_license_company();
|
||||
shopStoreCompany.setCompany_name(companyName);
|
||||
shopStoreCompany.setCompany_area(shopStoreBase.getStore_area());
|
||||
shopStoreCompany.setCompany_address(shopMchEntry.getStore_address());
|
||||
// 公司名
|
||||
String companyName = StrUtil.isBlank(shopMchEntry.getBiz_license_company()) ? shopMchEntry.getStore_name() : shopMchEntry.getBiz_license_company();
|
||||
shopStoreCompany.setCompany_name(companyName);
|
||||
shopStoreCompany.setCompany_area(shopStoreBase.getStore_area());
|
||||
shopStoreCompany.setCompany_address(shopMchEntry.getStore_address());
|
||||
|
||||
// 营业执照
|
||||
shopStoreCompany.setBusiness_id(shopMchEntry.getBiz_license_number());
|
||||
shopStoreCompany.setBusiness_license_electronic(shopMchEntry.getBiz_license_image());
|
||||
// 营业执照
|
||||
shopStoreCompany.setBusiness_id(shopMchEntry.getBiz_license_number());
|
||||
shopStoreCompany.setBusiness_license_electronic(shopMchEntry.getBiz_license_image());
|
||||
|
||||
// 企业法人
|
||||
shopStoreCompany.setLegal_person(shopMchEntry.getLegal_person_name());
|
||||
shopStoreCompany.setLegal_person_number(shopMchEntry.getLegal_person_id_number());
|
||||
shopStoreCompany.setLegal_person_electronic(shopMchEntry.getLegal_person_id_images());
|
||||
// 企业法人
|
||||
shopStoreCompany.setLegal_person(shopMchEntry.getLegal_person_name());
|
||||
shopStoreCompany.setLegal_person_number(shopMchEntry.getLegal_person_id_number());
|
||||
shopStoreCompany.setLegal_person_electronic(shopMchEntry.getLegal_person_id_images());
|
||||
|
||||
// 银行对公账号
|
||||
shopStoreCompany.setBank_account_name(shopMchEntry.getAccount_holder_name());
|
||||
shopStoreCompany.setBank_account_number(shopMchEntry.getAccount_number());
|
||||
shopStoreCompany.setBank_name(shopMchEntry.getBank_name());
|
||||
// 银行对公账号
|
||||
shopStoreCompany.setBank_account_name(shopMchEntry.getAccount_holder_name());
|
||||
shopStoreCompany.setBank_account_number(shopMchEntry.getAccount_number());
|
||||
shopStoreCompany.setBank_name(shopMchEntry.getBank_name());
|
||||
|
||||
Date today = new Date(); // 当前时间
|
||||
shopStoreCompany.setOrganization_code_start(today);
|
||||
shopStoreCompany.setOrganization_code_end(DateUtil.offsetDay(today, 365 * 5));// 五年
|
||||
shopStoreCompany.setEstablish_date(today);
|
||||
shopStoreCompany.setBusiness_licence_start(today);
|
||||
shopStoreCompany.setBusiness_licence_end(DateUtil.offsetDay(today, 365 * 10));
|
||||
Date today = new Date(); // 当前时间
|
||||
shopStoreCompany.setOrganization_code_start(today);
|
||||
shopStoreCompany.setOrganization_code_end(DateUtil.offsetDay(today, 365 * 5));// 五年
|
||||
shopStoreCompany.setEstablish_date(today);
|
||||
shopStoreCompany.setBusiness_licence_start(today);
|
||||
shopStoreCompany.setBusiness_licence_end(DateUtil.offsetDay(today, 365 * 10));
|
||||
|
||||
shopStoreCompany.setCompany_description(shopMchEntry.getStore_name());
|
||||
shopStoreCompany.setStore_class_ids("");
|
||||
shopStoreCompany.setStore_class_names("");
|
||||
shopStoreCompany.setStore_class_commission("");
|
||||
shopStoreCompany.setCompany_description(shopMchEntry.getStore_name());
|
||||
shopStoreCompany.setStore_class_ids("");
|
||||
shopStoreCompany.setStore_class_names("");
|
||||
shopStoreCompany.setStore_class_commission("");
|
||||
|
||||
if (!shopStoreCompanyService.save(shopStoreCompany)) {
|
||||
logger.error("生成店铺:新增店铺公司失败");
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("新增店铺公司失败"));
|
||||
}
|
||||
|
||||
return Pair.of(0, "新增店铺公司失败");
|
||||
}
|
||||
}
|
||||
|
||||
List<ShopStoreEmployee> shopStoreEmployees = shopStoreEmployeeService.selectEmployeeByCondition(storeId, null, null);
|
||||
|
||||
ShopStoreEmployee shopStoreEmployee = new ShopStoreEmployee();
|
||||
shopStoreEmployee.setStore_id(storeId);
|
||||
shopStoreEmployee.setUser_id(userId);
|
||||
shopStoreEmployee.setRights_group_id(""); // 店铺管理员,店铺
|
||||
shopStoreEmployee.setEmployee_is_kefu(CommonConstant.Enable);
|
||||
|
||||
if (CollUtil.isEmpty(shopStoreEmployees)) { // 添加管理员
|
||||
// shop_store_employee 店铺员工,添加管理员
|
||||
shopStoreEmployee.setEmployee_is_admin(CommonConstant.Enable);
|
||||
} else { // 添加店员或管理员
|
||||
shopStoreEmployees = shopStoreEmployeeService.selectEmployeeByCondition(storeId, userId, null);
|
||||
if (CollUtil.isEmpty(shopStoreEmployees)) {
|
||||
shopStoreEmployee.setEmployee_is_admin(CommonConstant.Disable);
|
||||
} else {
|
||||
shopStoreEmployee.setEmployee_is_admin(shopStoreEmployees.get(0).getEmployee_is_admin());
|
||||
}
|
||||
}
|
||||
|
||||
if (!shopStoreEmployeeService.save(shopStoreEmployee)) {
|
||||
logger.error("生成店铺:新增店铺员工失败");
|
||||
if (!shopStoreCompanyService.save(shopStoreCompany)) {
|
||||
logger.error("生成店铺:新增店铺公司失败");
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("新增店铺员工失败"));
|
||||
throw new ApiException(I18nUtil._("新增店铺公司失败"));
|
||||
}
|
||||
|
||||
return Pair.of(0, "新增店铺公司失败");
|
||||
}
|
||||
|
||||
|
||||
QueryWrapper<ShopStoreEmployee> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("store_id", storeId).eq("user_id", userId).eq("employee_is_admin", CommonConstant.Enable);
|
||||
if (shopStoreEmployeeService.count(queryWrapper) <= 0) {
|
||||
// shop_store_employee 店铺员工,添加管理员
|
||||
ShopStoreEmployee shopStoreEmployee = new ShopStoreEmployee();
|
||||
shopStoreEmployee.setStore_id(storeId);
|
||||
shopStoreEmployee.setUser_id(userId);
|
||||
shopStoreEmployee.setRights_group_id(""); // 店铺管理员,店铺
|
||||
shopStoreEmployee.setEmployee_is_admin(CommonConstant.Enable);
|
||||
shopStoreEmployee.setEmployee_is_kefu(CommonConstant.Enable);
|
||||
if (!shopStoreEmployeeService.save(shopStoreEmployee)) {
|
||||
logger.error("生成店铺:新增店铺员工失败");
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("新增店铺员工失败"));
|
||||
}
|
||||
return Pair.of(0, "新增店铺员工失败");
|
||||
}
|
||||
return Pair.of(0, "新增店铺员工失败");
|
||||
}
|
||||
|
||||
// 生成店铺的太阳码 2025-03-31
|
||||
@ -3368,10 +3331,13 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
}
|
||||
|
||||
// 注意:关联店铺到用户,给用户增加店铺管理员权限
|
||||
initStoreExtraInfo(userId, storeId, allowThrown);
|
||||
initStoreExtraInfo(userId, storeId);
|
||||
|
||||
// 更改店铺Id和状态
|
||||
shopMchEntryService.updateMerchEntryStoreStatus(shopMchEntry.getId(), storeId);
|
||||
// 更改店铺Id
|
||||
shopMchEntryService.updateMerchEntryStoreId(shopMchEntry.getId(), storeId);
|
||||
|
||||
// 初始化同城配送默认设置
|
||||
// storeSameCityTransportBaseService.initDefaultSameCityTransport(storeId);
|
||||
|
||||
// 立即创建顺丰店铺,附带初始化同城配送默认设置
|
||||
String[] areaNames = StrUtil.isNotBlank(shopMchEntry.getStore_area()) ? shopMchEntry.getStore_area().split("/") : new String[0];
|
||||
@ -3394,7 +3360,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
* @param userId
|
||||
* @param storeId
|
||||
*/
|
||||
private void initStoreExtraInfo(Integer userId, Integer storeId, Boolean allowThrown) {
|
||||
private void initStoreExtraInfo(Integer userId, Integer storeId) {
|
||||
if (ObjectUtil.isNull(userId) || ObjectUtil.isNull(storeId)) {
|
||||
return;
|
||||
}
|
||||
@ -3402,16 +3368,10 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
Date today = new Date(); // 当前时间
|
||||
|
||||
// 初始化时添加一条店铺分析信息
|
||||
ShopStoreAnalytics storeAnalytics = shopStoreAnalyticsService.getByStoreId(storeId);
|
||||
if (storeAnalytics == null) {
|
||||
storeAnalytics = new ShopStoreAnalytics();
|
||||
storeAnalytics.setStore_id(storeId);
|
||||
if (!shopStoreAnalyticsService.add(storeAnalytics)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
log.error("初始化店铺分析信息失败");
|
||||
}
|
||||
ShopStoreAnalytics store_analytics_column = new ShopStoreAnalytics();
|
||||
store_analytics_column.setStore_id(storeId);
|
||||
if (!shopStoreAnalyticsService.saveOrUpdate(store_analytics_column)) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
// 初始化店铺商品标签
|
||||
@ -3430,10 +3390,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
|
||||
if (CollUtil.isNotEmpty(store_product_tag_row)) {
|
||||
if (!shopStoreProductTagService.saveOrUpdate(store_product_tag_row)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
log.error("初始化店铺商品标签失败");
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3445,10 +3402,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
invoicingWarehouseBase.setWarehouse_number("");
|
||||
invoicingWarehouseBase.setWarehouse_contact("");
|
||||
if (!invoicingWarehouseBaseService.saveOrUpdate(invoicingWarehouseBase)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
log.error("初始化默认店铺仓库失败");
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
//初始化默认权限
|
||||
@ -3536,10 +3490,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
shopStoreEmployeeRightsGroups.add(extension2);
|
||||
|
||||
if (!shopStoreEmployeeRightsGroupService.saveOrUpdate(shopStoreEmployeeRightsGroups)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
log.error("初始化店铺员工默认权限失败");
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
// 添加店铺到用户
|
||||
@ -3553,9 +3504,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
.set("employee_is_admin", CommonConstant.Enable)
|
||||
.set("employee_is_kefu", CommonConstant.Enable);
|
||||
if (!shopStoreEmployeeService.update(queryWrapper)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("设置店铺管理员权限失败"));
|
||||
}
|
||||
// throw new ApiException(I18nUtil._("设置店铺管理员权限失败"));
|
||||
log.error("设置店铺管理员权限失败!");
|
||||
}
|
||||
|
||||
@ -3569,10 +3518,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
String storeIds = appendStoreIdToAccount(userId, storeId);
|
||||
accountUserBase.setStore_ids(storeIds); // 重要,给用户添加上这个店铺的归属权
|
||||
if (!accountService.saveOrUpdateUserBase(accountUserBase)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("店铺关联到用户失败"));
|
||||
}
|
||||
log.error("店铺关联到用户失败!");
|
||||
throw new ApiException(I18nUtil._("店铺关联到用户失败"));
|
||||
}
|
||||
|
||||
// 添加默认运输模板
|
||||
@ -3584,10 +3530,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
shopStoreTransportType.setTransport_type_freight_free(BigDecimal.ZERO); // 免运费额度
|
||||
shopStoreTransportType.setTransport_type_free(1);
|
||||
if (!shopStoreTransportTypeService.saveOrUpdate(shopStoreTransportType)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("添加运输模板失败"));
|
||||
}
|
||||
log.error("添加运输模板失败!");
|
||||
throw new ApiException(I18nUtil._("添加运输模板失败"));
|
||||
}
|
||||
|
||||
// 店铺配置
|
||||
@ -3626,24 +3569,18 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
shopStoreConfig.setSc_festival_amount_upper(BigDecimal.ZERO);
|
||||
shopStoreConfig.setSc_festival_float_proportion(BigDecimal.ZERO);
|
||||
if (!shopStoreConfigService.saveOrUpdate(shopStoreConfig)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("添加订单流转配置失败"));
|
||||
}
|
||||
log.error("添加订单流转配置失败!");
|
||||
throw new ApiException(I18nUtil._("添加订单流转配置失败"));
|
||||
}
|
||||
|
||||
// 添加默认客户等级
|
||||
InvoicingCustomerLevel invoicingCustomerLevel = new InvoicingCustomerLevel();
|
||||
invoicingCustomerLevel.setCustomer_level_name(I18nUtil._("普通(系统默认,不可删除)"));
|
||||
invoicingCustomerLevel.setCustomer_level_discountrate(new BigDecimal(100));
|
||||
invoicingCustomerLevel.setCustomer_level_discountrate(new BigDecimal("100"));
|
||||
invoicingCustomerLevel.setCustomer_level_is_buildin(1);
|
||||
invoicingCustomerLevel.setCustomer_level_desc("");
|
||||
|
||||
if (!invoicingCustomerLevelService.saveOrUpdate(invoicingCustomerLevel)) {
|
||||
if (allowThrown) {
|
||||
throw new ApiException(I18nUtil._("添加默认客户等级失败"));
|
||||
}
|
||||
log.error("添加默认客户等级失败!");
|
||||
throw new ApiException(I18nUtil._("添加默认客户等级失败"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3705,54 +3642,50 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
* 获取店铺的分账比例
|
||||
* 根据店铺的大分、小分类、来计算分账比例
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param storeId
|
||||
* @param reCalculate 是否根据店铺的分类来重新计算
|
||||
* @return 平台分账比例的数值
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal getStoreSplitRatio(Integer storeId, boolean reCalculate) {
|
||||
log.debug("开始获取店铺分账比例,storeId={}, reCalculate={}", storeId, reCalculate);
|
||||
|
||||
// 定义默认分账比例
|
||||
final BigDecimal defaultSplitRatio = BigDecimal.valueOf(94);
|
||||
BigDecimal defaultSplitRatio = new BigDecimal("100");
|
||||
if (storeId == null || storeId <= 0) {
|
||||
log.warn("店铺ID无效,使用默认分账比例: {}", defaultSplitRatio);
|
||||
return defaultSplitRatio;
|
||||
}
|
||||
|
||||
BigDecimal splitRatio = null;
|
||||
|
||||
// 获取店铺基础信息
|
||||
ShopStoreBase shopStoreBase = get(storeId);
|
||||
log.debug("获取店铺基础信息完成,shopStoreBase={}",
|
||||
shopStoreBase != null ? shopStoreBase.getStore_id() : null);
|
||||
|
||||
if (shopStoreBase != null) {
|
||||
// 获取店铺已配置的分账比例
|
||||
splitRatio = CheckUtil.isEmpty(shopStoreBase.getSplit_ratio()) ? null : shopStoreBase.getSplit_ratio();
|
||||
log.debug("从店铺基础信息获取分账比例: {}", splitRatio);
|
||||
if (shopStoreBase == null) {
|
||||
return defaultSplitRatio;
|
||||
}
|
||||
|
||||
// 获取店铺已配置的分账比例
|
||||
BigDecimal splitRatio = shopStoreBase.getSplit_ratio();
|
||||
|
||||
// 如果没有配置或需要重新计算,则基于店铺分类获取比例
|
||||
if (reCalculate || splitRatio == null) {
|
||||
log.debug("需要重新计算分账比例或当前比例为空,基于店铺分类计算");
|
||||
Integer storeCategoryId = shopStoreBase.getStore_category_id();
|
||||
if (storeCategoryId == null) {
|
||||
return defaultSplitRatio; // 默认 100%
|
||||
}
|
||||
|
||||
// 通过商户入驻服务计算分账比例,传入null作为一级分类,店铺分类ID作为二级分类
|
||||
splitRatio = shopMchEntryService.getMchEntryRatioOrDefault(shopStoreBase.getStore_category_id(), shopStoreBase.getStore_2nd_category_id(), splitRatio, defaultSplitRatio);
|
||||
log.debug("通过商户入驻服务计算分账比例: {}", splitRatio);
|
||||
// 获取店铺分类信息
|
||||
ShopBaseStoreCategory category = shopBaseStoreCategoryService.get(storeCategoryId);
|
||||
if (category != null && category.getSplit_ratio() != null) {
|
||||
splitRatio = category.getSplit_ratio();
|
||||
} else {
|
||||
splitRatio = defaultSplitRatio; // 默认值
|
||||
}
|
||||
|
||||
// 确保比例不超过 100%
|
||||
if (splitRatio.compareTo(BigDecimal.ZERO) < 0 || splitRatio.compareTo(defaultSplitRatio) > 0) {
|
||||
splitRatio = defaultSplitRatio;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保比例在有效范围内 (0%, 100%)
|
||||
if (splitRatio != null && (splitRatio.compareTo(BigDecimal.ZERO) <= 0 || splitRatio.compareTo(BigDecimal.valueOf(100)) >= 0)) {
|
||||
log.warn("分账比例超出有效范围 (0, 100),使用默认分账比例: {},当前比例: {}", defaultSplitRatio, splitRatio);
|
||||
splitRatio = defaultSplitRatio;
|
||||
}
|
||||
|
||||
log.info("获取店铺分账比例完成,storeId={}, splitRatio={}", storeId, splitRatio);
|
||||
return splitRatio;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改店铺的营业状态
|
||||
*
|
||||
@ -4099,48 +4032,6 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新店铺分账比例
|
||||
*
|
||||
* @param storeId 店铺ID
|
||||
* @param splitRatio 分账比例
|
||||
* @return 更新结果,成功返回true,失败返回false
|
||||
*/
|
||||
protected Boolean updateStoreBaseSplitRatio(Integer storeId, BigDecimal splitRatio) {
|
||||
log.debug("开始更新店铺分账比例,storeId={}, splitRatio={}", storeId, splitRatio);
|
||||
|
||||
// 参数校验
|
||||
if (storeId == null || storeId <= 0) {
|
||||
log.warn("更新店铺分账比例参数校验失败,storeId不能为空或小于等于0");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (splitRatio == null || splitRatio.compareTo(BigDecimal.ZERO) <= 0
|
||||
|| splitRatio.compareTo(BigDecimal.valueOf(100)) >= 0) {
|
||||
log.warn("更新店铺分账比例参数校验失败,splitRatio 值无效");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
UpdateWrapper<ShopStoreBase> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("store_id", storeId);
|
||||
updateWrapper.set("split_ratio", splitRatio);
|
||||
|
||||
boolean result = update(updateWrapper);
|
||||
if (result) {
|
||||
log.info("店铺分账比例更新成功,storeId={}, splitRatio={}", storeId, splitRatio);
|
||||
} else {
|
||||
log.warn("店铺分账比例更新失败,storeId={}, splitRatio={}", storeId, splitRatio);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("更新店铺分账比例时发生异常,storeId={}, splitRatio={}", storeId, splitRatio, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public Page<ShopStoreBase> getMobileStoreList(Integer page, Integer rows) {
|
||||
// QueryWrapper<ShopStoreBase> queryWrapper=new QueryWrapper<>();
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.suisung.mall.shop.store.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.suisung.mall.common.api.ResultCode;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.modules.store.ShopStoreCompany;
|
||||
@ -31,19 +30,6 @@ public class ShopStoreCompanyServiceImpl extends BaseServiceImpl<ShopStoreCompan
|
||||
@Autowired
|
||||
private ShopStoreEmployeeService shopStoreEmployeeService;
|
||||
|
||||
/**
|
||||
* 获取店铺公司信息
|
||||
*
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ShopStoreCompany getCompany(Integer storeId) {
|
||||
QueryWrapper<ShopStoreCompany> queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq("store_id", storeId).orderByAsc("company_id");
|
||||
return findOne(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveOrUpdateCompany(ShopStoreCompany shopStoreCompany) {
|
||||
|
||||
|
||||
@ -243,33 +243,6 @@ public class ShopStoreEmployeeServiceImpl extends BaseServiceImpl<ShopStoreEmplo
|
||||
return shopStoreEmployeeMapper.selectByStoreIdRightGroupId(storeId, rightsGroupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据店铺Id和员工Id获取员工信息
|
||||
*
|
||||
* @param storeId
|
||||
* @param userId
|
||||
* @param isAdmin
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<ShopStoreEmployee> selectEmployeeByCondition(Integer storeId, Integer userId, Boolean isAdmin) {
|
||||
if (CheckUtil.isEmpty(storeId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
QueryWrapper<ShopStoreEmployee> queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
if (CheckUtil.isNotEmpty(userId)) {
|
||||
queryWrapper.eq("user_id", userId);
|
||||
}
|
||||
|
||||
if (isAdmin != null) {
|
||||
queryWrapper.eq("employee_is_admin", isAdmin);
|
||||
}
|
||||
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据店铺Id获取店铺的所有员工的个推 CID 列表
|
||||
*
|
||||
|
||||
@ -6,11 +6,10 @@ import java.math.RoundingMode;
|
||||
public class ProductPriceCalculator {
|
||||
/**
|
||||
* 计算切割后的商品单价和数量
|
||||
*
|
||||
* @param unitPricePerKg 千克单价(元/千克)
|
||||
* @param totalWeightKg 总重量(千克)
|
||||
* @param pieceWeight 切割单位重量(数值)
|
||||
* @param weightUnit 重量单位("g"=克,"kg"=千克)
|
||||
* @param totalWeightKg 总重量(千克)
|
||||
* @param pieceWeight 切割单位重量(数值)
|
||||
* @param weightUnit 重量单位("g"=克,"kg"=千克)
|
||||
* @return 包含两个元素的数组:[切割后单价(元/单位), 完整单位数量]
|
||||
*/
|
||||
public static BigDecimal[] calculatePriceAndQuantity(
|
||||
@ -71,7 +70,7 @@ public class ProductPriceCalculator {
|
||||
|
||||
// 千克单位示例
|
||||
BigDecimal[] result3 = calculatePriceAndQuantity(
|
||||
new BigDecimal(100),
|
||||
new BigDecimal("100"),
|
||||
new BigDecimal("2.5"),
|
||||
new BigDecimal("0.5"),
|
||||
"kg");
|
||||
|
||||
@ -57,7 +57,7 @@ public class ShopBatchSubmitListener extends AnalysisEventListener<SxGoosModelEx
|
||||
this.syncThirdDataService = syncThirdDataService;
|
||||
this.syncStoreSpecsService = syncStoreSpecsService;
|
||||
// 创建线程池(根据CPU核心数优化)
|
||||
// int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||
// int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||
// log.info("核心线程数量{}", corePoolSize);
|
||||
this.executorService = Executors.newFixedThreadPool(6);
|
||||
this.futures = new ArrayList<>();
|
||||
@ -74,7 +74,7 @@ public class ShopBatchSubmitListener extends AnalysisEventListener<SxGoosModelEx
|
||||
sxGoosModelExcel.setProduct_barcode("1");
|
||||
sxGoosModelExcel.setProduct_name("产品1");
|
||||
sxGoosModelExcel.setShop_specs("颜色");
|
||||
sxGoosModelExcel.setRetail_price(new BigDecimal(100));
|
||||
sxGoosModelExcel.setRetail_price(new BigDecimal("100"));
|
||||
sxGoosModelExcel.setStock(new BigDecimal("10"));
|
||||
sxGoosModelExcel.setJsonSpecs("[颜色:红色][尺寸:10]");
|
||||
|
||||
|
||||
@ -121,5 +121,4 @@ job:
|
||||
- "UpdatePayCardStateJob"
|
||||
- "RetryMqMsgJob"
|
||||
- "ProductItemAutoFillJob"
|
||||
- "XcxSubSendMessageJob"
|
||||
- "UpdateOrderSeparateJob"
|
||||
- "XcxSubSendMessageJob"
|
||||
@ -168,7 +168,7 @@ lakala:
|
||||
client_id: lsycs
|
||||
client_secret: XPa1HB5d55Ig0qV8
|
||||
user_no: 29153396
|
||||
split_lowest_ratio: 20.00
|
||||
split_lowest_ratio: 94.00
|
||||
activity_id: 687
|
||||
wx_fee: 0.6 # 微信手续费 6/1000
|
||||
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
|
||||
|
||||
@ -147,34 +147,34 @@ sf-express:
|
||||
#拉卡拉进件配置
|
||||
lakala:
|
||||
#服务地址
|
||||
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
|
||||
is_prod: true
|
||||
org_code: 1951582
|
||||
is_prod: false
|
||||
# 拉卡拉拓客进件配置
|
||||
tk:
|
||||
#服务地址
|
||||
server_url: https://tkapi.lakala.com
|
||||
client_id: gpff
|
||||
client_secret: uRjvaJkWS1A0VsAv
|
||||
user_no: 22874827
|
||||
split_lowest_ratio: 20.00
|
||||
activity_id: 208
|
||||
wx_fee: 0.25 # 微信手续费 千分之2.5
|
||||
api_pub_key_path: payKey/lakala/prod/tk_api_public_key.txt
|
||||
api_pri_key_path: payKey/lakala/prod/tk_api_private_key.txt
|
||||
notify_pub_key_path: payKey/lakala/prod/tk_notify_public_key.txt
|
||||
notify_pri_key_path: payKey/lakala/prod/tk_notify_private_key.txt
|
||||
|
||||
server_url: https://test.wsmsd.cn
|
||||
client_id: lsycs
|
||||
client_secret: XPa1HB5d55Ig0qV8
|
||||
user_no: 29153396
|
||||
split_lowest_ratio: 94.00
|
||||
activity_id: 687
|
||||
wx_fee: 0.6 # 微信手续费 6/1000
|
||||
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
|
||||
|
||||
@ -183,7 +183,7 @@ lakala:
|
||||
client_id: gpff
|
||||
client_secret: uRjvaJkWS1A0VsAv
|
||||
user_no: 22874827
|
||||
split_lowest_ratio: 20.00
|
||||
split_lowest_ratio: 94.00
|
||||
activity_id: 208
|
||||
wx_fee: 0.25 # 微信手续费 千分之2.5
|
||||
api_pub_key_path: payKey/lakala/prod/tk_api_public_key.txt
|
||||
|
||||
@ -172,7 +172,7 @@ lakala:
|
||||
client_id: lsycs
|
||||
client_secret: XPa1HB5d55Ig0qV8
|
||||
user_no: 29153396
|
||||
split_lowest_ratio: 20.00
|
||||
split_lowest_ratio: 94.00
|
||||
activity_id: 687
|
||||
wx_fee: 0.6 # 微信手续费 6/1000
|
||||
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
|
||||
|
||||
@ -172,7 +172,7 @@ lakala:
|
||||
client_id: lsycs
|
||||
client_secret: XPa1HB5d55Ig0qV8
|
||||
user_no: 29153396
|
||||
split_lowest_ratio: 20.00
|
||||
split_lowest_ratio: 94.00
|
||||
activity_id: 687
|
||||
wx_fee: 0.6 # 微信手续费 6/1000
|
||||
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
|
||||
|
||||
@ -17,15 +17,15 @@
|
||||
JOIN lkl_area c on c.area_code=b.parent_code and c.type=b.type
|
||||
<where>
|
||||
<if test="bankNo!=null and bankNo!=''">
|
||||
and a.bank_no = #{bankNo}
|
||||
and bank_no = #{bankNo}
|
||||
</if>
|
||||
|
||||
<if test="branchBankNo!=null and branchBankNo!=''">
|
||||
and a.branch_bank_no = #{branchBankNo}
|
||||
and branch_bank_no = #{branchBankNo}
|
||||
</if>
|
||||
|
||||
<if test="clearNo!=null and clearNo!=''">
|
||||
and a.clear_no = #{clearNo}
|
||||
<if test="branchBankNo!=null and branchBankNo!=''">
|
||||
and branch_bank_no = #{branchBankNo}
|
||||
</if>
|
||||
|
||||
<choose>
|
||||
@ -40,7 +40,7 @@
|
||||
<if test="keywords!=null and keywords.size>0">
|
||||
AND (
|
||||
<foreach collection="keywords" item="keyword" separator="AND">
|
||||
a.branch_bank_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
branch_bank_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
|
||||
@ -5,8 +5,7 @@
|
||||
<sql id="Base_Column_List">
|
||||
store_id
|
||||
, user_id, store_name, store_grade_id, store_logo, store_slogan, store_domain, store_area, store_district_id,
|
||||
store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open, store_biz_state,
|
||||
ringtone_is_enable, shop_parent_id, store_2nd_category_id,
|
||||
store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open, store_biz_state, shop_parent_id,
|
||||
store_category_id, store_state_id, store_time, store_end_time, product_category_ids, store_o2o_tags,
|
||||
store_o2o_flag, store_o2o_merchant_id, store_circle, subsite_id, lkl_merchant_no, lkl_term_no, wx_qrcode,
|
||||
split_ratio, packing_fee, created_at, updated_at
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,368 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||
<title>小发同城电子合同签署</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4CAF50, #2E7D32);
|
||||
color: white;
|
||||
padding: 30px 20px 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 30px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #e8f5e9;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.success-icon span {
|
||||
font-size: 40px;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.message {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.message p {
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.message p:first-child {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.link-container {
|
||||
background-color: #f0f9ff;
|
||||
border: 1px dashed #2196F3;
|
||||
border-radius: 12px;
|
||||
padding: 20px 15px;
|
||||
margin: 25px 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.link-title {
|
||||
font-weight: 500;
|
||||
color: #1976D2;
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #1976D2;
|
||||
word-break: break-all;
|
||||
font-size: 15px;
|
||||
font-family: monospace;
|
||||
padding: 10px;
|
||||
background-color: #e3f2fd;
|
||||
border-radius: 8px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.app-option {
|
||||
background-color: #fff3e0;
|
||||
border: 1px solid #ffcc80;
|
||||
border-radius: 12px;
|
||||
padding: 20px 15px;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-option p {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #e65100;
|
||||
}
|
||||
|
||||
.app-icon {
|
||||
font-size: 36px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: #fff8e1;
|
||||
border-left: 4px solid #ffc107;
|
||||
padding: 15px;
|
||||
margin: 25px 0;
|
||||
text-align: left;
|
||||
border-radius: 0 6px 6px 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.warning strong {
|
||||
color: #e65100;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #fafafa;
|
||||
padding: 20px 15px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.contact {
|
||||
color: #1976D2;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.contact:hover, .contact:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, #2196F3, #1976D2);
|
||||
color: white;
|
||||
text-align: center;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
margin: 20px 0;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 6px rgba(33, 150, 243, 0.2);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 2px 3px rgba(33, 150, 243, 0.2);
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
background: #e3f2fd;
|
||||
color: #1976D2;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 移动端优化 */
|
||||
@media (max-width: 480px) {
|
||||
.header {
|
||||
padding: 25px 15px 15px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.success-icon span {
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
.message p {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.message p:first-child {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.link-container, .app-option {
|
||||
padding: 15px 12px;
|
||||
}
|
||||
|
||||
.link {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕优化 */
|
||||
@media (max-width: 360px) {
|
||||
body {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 14px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>小发同城电子合同签署</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="success-icon">
|
||||
<span>✓</span>
|
||||
</div>
|
||||
|
||||
<div class="message">
|
||||
<p>恭喜!您的开店入驻申请已审核通过</p>
|
||||
<p>请在24小时内完成电子合同签署</p>
|
||||
|
||||
<div class="link-container">
|
||||
<div class="link-title">合作方签署链接(24小时内有效)</div>
|
||||
<div class="link" id="signLink" th:text="${resultUrl}">${resultUrl}</div>
|
||||
<button class="btn copy-btn" onclick="copyLink()">复制链接</button>
|
||||
</div>
|
||||
|
||||
<!-- <div class="app-option">-->
|
||||
<!-- <div class="app-icon">📱</div>-->
|
||||
<!-- <p>或前往<strong>小发商家版APP</strong>完成签署</p>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<button class="btn" onclick="openLink()">立即签署合同</button>
|
||||
|
||||
<div class="warning">
|
||||
<strong>注意:</strong>链接有效期为24小时,逾期需重新提交申请。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>如有疑问请联系客服:<a class="contact" href="tel:17777525395">17777525395</a></p>
|
||||
<p>感谢您对小发同城的支持!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script th:inline="javascript">
|
||||
// 获取后端传递的resultUrl变量
|
||||
var resultUrl = '${resultUrl}';
|
||||
|
||||
// 复制链接功能
|
||||
function copyLink() {
|
||||
var linkText = document.getElementById('signLink').textContent;
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(linkText).then(() => {
|
||||
alert('链接已复制到剪贴板');
|
||||
}).catch(err => {
|
||||
console.error('复制失败:', err);
|
||||
fallbackCopyTextToClipboard(linkText);
|
||||
});
|
||||
} else {
|
||||
fallbackCopyTextToClipboard(linkText);
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容性复制方法
|
||||
function fallbackCopyTextToClipboard(text) {
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
textArea.style.position = "fixed";
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
var successful = document.execCommand('copy');
|
||||
if (successful) {
|
||||
alert('链接已复制到剪贴板');
|
||||
} else {
|
||||
prompt("请手动复制以下链接:", text);
|
||||
}
|
||||
} catch (err) {
|
||||
prompt("请手动复制以下链接:", text);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
|
||||
// 打开链接功能
|
||||
function openLink() {
|
||||
if (resultUrl) {
|
||||
// 如果是完整URL则直接跳转
|
||||
if (resultUrl.startsWith('http') || resultUrl.startsWith('https')) {
|
||||
window.location.href = resultUrl;
|
||||
} else {
|
||||
// 否则添加协议前缀
|
||||
window.location.href = 'https://' + resultUrl;
|
||||
}
|
||||
} else {
|
||||
alert('链接无效,请联系客服');
|
||||
}
|
||||
}
|
||||
|
||||
// 检测是否在微信中打开
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('micromessenger')) {
|
||||
// 在微信中显示提示
|
||||
var btn = document.querySelector('.btn');
|
||||
if (btn) {
|
||||
btn.textContent = '点击右上角菜单选择在浏览器中打开';
|
||||
}
|
||||
}
|
||||
|
||||
// 防止页面被嵌入到iframe中
|
||||
if (window.self !== window.top) {
|
||||
window.top.location = window.location;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user