Compare commits
8 Commits
abd8f7aa60
...
14b32f6d07
Author | SHA1 | Date |
---|---|---|
|
14b32f6d07 | |
|
17f5807af6 | |
|
e18463279b | |
|
7e06c9f73f | |
|
38cb4a1595 | |
|
92ba2b93a2 | |
|
980d279ba9 | |
|
6f2eaf92a8 |
|
@ -1,12 +1,16 @@
|
|||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.shop.approval.ReturnApprovalApplicationService;
|
||||
import com.agileboot.domain.shop.approval.command.AddReturnApprovalCommand;
|
||||
import com.agileboot.domain.shop.approval.command.UpdateReturnApprovalCommand;
|
||||
import com.agileboot.domain.shop.approval.db.ReturnApprovalEntity;
|
||||
import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
|
||||
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
|
||||
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery;
|
||||
import com.agileboot.domain.shop.order.OrderApplicationService;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
|
||||
|
@ -14,14 +18,11 @@ import io.swagger.annotations.Api;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
|
@ -37,13 +38,48 @@ import java.util.Date;
|
|||
@Slf4j
|
||||
@Api(tags = "审批接口")
|
||||
public class ApprovalApiController {
|
||||
|
||||
|
||||
/** 退货审批应用服务,用于处理审批相关业务逻辑 */
|
||||
private final ReturnApprovalApplicationService approvalApplicationService;
|
||||
|
||||
|
||||
/** 订单应用服务,用于处理订单相关查询操作 */
|
||||
private final OrderApplicationService orderApplicationService;
|
||||
|
||||
/**
|
||||
* 处理审批操作
|
||||
*
|
||||
* @param command 包含审批操作信息的命令对象
|
||||
* @return 操作结果响应
|
||||
* @throws ApiException 当参数校验失败或业务逻辑出错时抛出
|
||||
*/
|
||||
@PostMapping("/handle")
|
||||
@ApiOperation(value = "处理审批操作")
|
||||
public ResponseDTO<String> handleApproval(@Valid @RequestBody UpdateReturnApprovalCommand command) {
|
||||
if (command.getApprovalId() == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "审批ID不能为空"));
|
||||
}
|
||||
if (command.getStatus() == null) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "操作状态不能为空"));
|
||||
}
|
||||
|
||||
try {
|
||||
if (command.getStatus() == 2) {
|
||||
if (command.getReturnAmount() == null || command.getReturnAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "归还金额不能为空或小于等于0"));
|
||||
}
|
||||
approvalApplicationService.approveApproval(command);
|
||||
} else if (command.getStatus() == 3) {
|
||||
approvalApplicationService.rejectApproval(command);
|
||||
} else {
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "无效的操作状态"));
|
||||
}
|
||||
return ResponseDTO.ok("操作成功");
|
||||
} catch (Exception e) {
|
||||
log.error("审批操作失败", e);
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交退货审批申请
|
||||
*
|
||||
|
@ -74,4 +110,11 @@ public class ApprovalApiController {
|
|||
ReturnApprovalEntity returnApproval = approvalApplicationService.submitApproval(command, orderGoods);
|
||||
return ResponseDTO.ok(returnApproval);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation(value = "审批列表")
|
||||
public ResponseDTO<PageDTO<ReturnApprovalEntity>> list(SearchApiReturnApprovalQuery<ReturnApprovalEntity> query) {
|
||||
PageDTO<ReturnApprovalEntity> page = approvalApplicationService.getApprovalWithGoodsInfo(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ import java.math.BigDecimal;
|
|||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* 调度日志操作处理
|
||||
*
|
||||
* @author valarchie
|
||||
* 订单控制器,处理与订单相关的HTTP请求
|
||||
* 包括订单提交、开柜门、查询订单和退款等操作
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
|
@ -33,25 +32,48 @@ public class OrderController extends BaseController {
|
|||
private final OrderApplicationService orderApplicationService;
|
||||
private final PaymentApplicationService paymentApplicationService;
|
||||
|
||||
// 新增提交订单接口
|
||||
/**
|
||||
* 提交订单接口
|
||||
* @param command 提交订单的请求参数
|
||||
* @return 包含订单创建结果的响应
|
||||
*/
|
||||
@PostMapping("/submit")
|
||||
public ResponseDTO<CreateOrderResult> submitOrder(@Validated @RequestBody SubmitOrderCommand command) {
|
||||
CreateOrderResult result = orderApplicationService.createOrder(command);
|
||||
return ResponseDTO.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开订单商品柜门接口
|
||||
* @param orderId 订单ID
|
||||
* @param orderGoodsId 订单商品ID
|
||||
* @return 空响应
|
||||
*/
|
||||
@PostMapping("/openCabinet/{orderId}/{orderGoodsId}")
|
||||
public ResponseDTO<?> openCabinet(@PathVariable Long orderId, @PathVariable Long orderGoodsId) {
|
||||
orderApplicationService.openOrderGoodsCabinet(orderId, orderGoodsId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户openid获取订单列表
|
||||
* @param openid 用户微信openid
|
||||
* @return 包含订单列表的响应
|
||||
*/
|
||||
@GetMapping("/user/{openid}")
|
||||
public ResponseDTO<GetOrdersByOpenIdDTO> getOrdersByOpenId(@PathVariable String openid) {
|
||||
GetOrdersByOpenIdDTO result = orderApplicationService.getOrdersByOpenId(openid);
|
||||
return ResponseDTO.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单退款接口
|
||||
* @param orderId 订单ID
|
||||
* @param money 退款金额(单位:分)
|
||||
* @return 包含退款结果的响应
|
||||
* @throws IllegalArgumentException 当退款金额为负数或超过订单总额时抛出
|
||||
* @throws RuntimeException 当退款过程中发生其他错误时抛出
|
||||
*/
|
||||
@PostMapping("/refund/{orderId}")
|
||||
public ResponseDTO<RefundVO> refundOrder(@PathVariable Long orderId, @RequestParam int money) {
|
||||
OrderModel orderModel = orderApplicationService.loadById(orderId);
|
||||
|
@ -74,7 +96,10 @@ public class OrderController extends BaseController {
|
|||
log.info("退款结果:{}", refundVO);
|
||||
return ResponseDTO.ok(refundVO);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
RefundVO refundVO = new RefundVO();
|
||||
refundVO.setSuccess(false);
|
||||
refundVO.setMsg(e.getMessage());
|
||||
return ResponseDTO.fail(refundVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.agileboot.domain.ab98.api.Ab98ApiUtil;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wx/login")
|
||||
@CrossOrigin(origins = "*", allowedHeaders = "*")
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "微信登录接口")
|
||||
public class WxLoginController {
|
||||
|
||||
@PostMapping("/logout")
|
||||
@ApiOperation(value = "用户退出登录")
|
||||
public ResponseDTO<Ab98ApiUtil.LogoutData> logout(@RequestParam @NotBlank String token) {
|
||||
try {
|
||||
return ResponseDTO.ok(Ab98ApiUtil.doLogout(token).getOutputData());
|
||||
} catch (ApiException e) {
|
||||
return ResponseDTO.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信登录二维码链接
|
||||
*/
|
||||
@GetMapping("/wechat/qrcode")
|
||||
public ResponseDTO<String> getWechatQrCode(@RequestParam @NotBlank String token) {
|
||||
try {
|
||||
return ResponseDTO.ok(Ab98ApiUtil.generateWechatLoginUrl(token));
|
||||
} catch (ApiException e) {
|
||||
return ResponseDTO.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取临时token
|
||||
*/
|
||||
@GetMapping("/getToken")
|
||||
@ApiOperation(value = "获取临时令牌", notes = "用于后续登录流程")
|
||||
public ResponseDTO<Ab98ApiUtil.TokenData> getToken(@RequestParam String appName) {
|
||||
try {
|
||||
return ResponseDTO.ok(Ab98ApiUtil.getToken(appName).getOutputData());
|
||||
} catch (ApiException e) {
|
||||
return ResponseDTO.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
*/
|
||||
@PostMapping("/sendSms")
|
||||
public ResponseDTO<Ab98ApiUtil.SmsResult> sendSms(
|
||||
@RequestParam String token,
|
||||
@RequestParam String tel) {
|
||||
try {
|
||||
return ResponseDTO.ok(Ab98ApiUtil.sendLoginSms(token, tel).getOutputData());
|
||||
} catch (ApiException e) {
|
||||
return ResponseDTO.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证短信验证码
|
||||
*/
|
||||
@PostMapping("/verifySms")
|
||||
public ResponseDTO<Ab98ApiUtil.LoginData> verifySms(
|
||||
@RequestParam String token,
|
||||
@RequestParam String tel,
|
||||
@RequestParam String vcode) {
|
||||
try {
|
||||
Ab98ApiUtil.LoginResponse loginResponse = Ab98ApiUtil.verifySmsCode(token, tel, vcode);
|
||||
Ab98ApiUtil.LoginData data = new Ab98ApiUtil.LoginData();
|
||||
data.setFace_img(loginResponse.getOutputData().getFace_img());
|
||||
data.setSuccess(loginResponse.getOutputData().isSuccess());
|
||||
data.setSex(loginResponse.getOutputData().getSex());
|
||||
data.setName(loginResponse.getOutputData().getName());
|
||||
data.setUserid(loginResponse.getOutputData().getUserid());
|
||||
data.setRegistered(loginResponse.getOutputData().isRegistered());
|
||||
data.setTel(loginResponse.getOutputData().getTel());
|
||||
return ResponseDTO.ok(data);
|
||||
} catch (ApiException e) {
|
||||
return ResponseDTO.fail(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,5 +3,8 @@ package com.agileboot.common.constant;
|
|||
public class PayApiConstants {
|
||||
public static final String biz_id = "wxshop";
|
||||
public static final String appkey = "wxshop202503081132";
|
||||
|
||||
public static final String pay_url = "http://222.218.10.217:7890/open/trade/wx/jsapi/precreate";
|
||||
public static final String pay_callback_url = "http://wxshop.ab98.cn/shop-api/api/payment/callback";
|
||||
public static final String refund_url = "http://222.218.10.217:7890/open/trade/refund";
|
||||
public static final String refund_callback_url = "http://wxshop.ab98.cn/shop-api/api/payment/refund/callback";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
package com.agileboot.domain.ab98.api;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class Ab98ApiUtil {
|
||||
|
||||
private static final String BASE_URL = "https://www.ab98.cn/api/doInterface";
|
||||
private static final String WEBSOCKET_URL = "wss://www.ab98.cn/login.ws/";
|
||||
|
||||
/**
|
||||
* 短信登录(发送验证码)
|
||||
*/
|
||||
/**
|
||||
* 发送短信验证码(短信登录)
|
||||
* @param token 通过getToken获取的临时令牌(有效期5分钟)
|
||||
* @param tel 接收验证码的手机号码(需符合格式:11位数字)
|
||||
* @param nobind "true"表示不绑定手机号(固定值)
|
||||
* @param for_login "true"表示用于登录(固定值)
|
||||
* @param from 来源渠道(固定值"jt")
|
||||
*/
|
||||
public static SmsSendResponse sendLoginSms(String token, String tel) {
|
||||
String url = BASE_URL + "?code=doSendSms";
|
||||
|
||||
Map<String, Object> paramMap = new HashMap<String, Object>() {{
|
||||
put("token", token);
|
||||
put("tel", tel);
|
||||
put("nobind", "true");
|
||||
put("for_login", "true");
|
||||
put("from", "jt");
|
||||
}};
|
||||
|
||||
String response = HttpUtil.createPost(url)
|
||||
.body(JSONUtil.toJsonStr(paramMap))
|
||||
.header("noSign", "true")
|
||||
.header("source", "api")
|
||||
.execute().body();
|
||||
log.info("短信发送响应: {}", response);
|
||||
|
||||
SmsSendResponse resp = JSONUtil.toBean(response, SmsSendResponse.class);
|
||||
checkApiResponse(resp);
|
||||
return resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证短信验证码
|
||||
*/
|
||||
/**
|
||||
* 验证短信验证码(短信登录)
|
||||
* @param token 通过getToken获取的临时令牌
|
||||
* @param tel 接收验证码的手机号码
|
||||
* @param vcode 用户输入的6位验证码(有效期5分钟)
|
||||
* @return 登录结果,包含用户身份信息
|
||||
* @throws ApiException 当验证失败或接口返回异常时抛出
|
||||
*/
|
||||
public static LoginResponse verifySmsCode(String token, String tel, String vcode) {
|
||||
String url = BASE_URL + "?code=doCheckSmsCode";
|
||||
|
||||
Map<String, Object> paramMap = new HashMap<String, Object>() {{
|
||||
put("token", token);
|
||||
put("tel", tel);
|
||||
put("vcode", vcode);
|
||||
}};
|
||||
|
||||
String response = HttpUtil.createPost(url)
|
||||
.body(JSONUtil.toJsonStr(paramMap))
|
||||
.header("noSign", "true")
|
||||
.header("source", "api")
|
||||
.execute().body();
|
||||
log.info("短信验证响应: {}", response);
|
||||
|
||||
LoginResponse resp = JSONUtil.toBean(response, LoginResponse.class);
|
||||
checkApiResponse(resp);
|
||||
return handleLoginResult(resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理登录结果
|
||||
*/
|
||||
private static LoginResponse handleLoginResult(LoginResponse response) {
|
||||
if (response.getOutputData() == null || !response.getOutputData().isSuccess()) {
|
||||
log.error("登录失败: {}", response);
|
||||
throw new ApiException(ErrorCode.FAILED, "登录验证失败");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成微信扫码登录URL
|
||||
*/
|
||||
public static String generateWechatLoginUrl(String token) {
|
||||
return "https://www.ab98.cn/online/index.html?content=doLogin%60" + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听扫码登录websocket
|
||||
*/
|
||||
/*public static void listenLoginWebsocket(String token, WebSocketListener listener) {
|
||||
String url = WEBSOCKET_URL + token;
|
||||
HttpUtil.createWebSocket(url, listener).connect();
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 获取登录token
|
||||
*/
|
||||
/**
|
||||
* 获取登录token
|
||||
* @param appName 应用英文名(需在汇邦数字平台登记)
|
||||
* @return outputData.token 临时令牌(后续接口需携带)
|
||||
* @return outputData.takeFace 是否需要人脸验证(true需要刷脸)
|
||||
*/
|
||||
public static TokenResponse getToken(String appName) {
|
||||
// String url = BASE_URL + "?code=doGetToken&from=jt&app=" + appName;
|
||||
String url = BASE_URL + "?code=doGetToken&from=jt";
|
||||
|
||||
String response = HttpUtil.createGet(url)
|
||||
.header("noSign", "true")
|
||||
.header("source", "api")
|
||||
.execute().body();
|
||||
log.info("获取token响应: {}", response);
|
||||
|
||||
TokenResponse tokenResponse = JSONUtil.toBean(response, TokenResponse.class);
|
||||
checkApiResponse(tokenResponse);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建带参数的请求URL
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 检查接口响应状态
|
||||
*/
|
||||
private static void checkApiResponse(BaseResponse response) {
|
||||
if (!"ok".equals(response.getState())) {
|
||||
log.error("接口调用失败: {}", response);
|
||||
throw new ApiException(ErrorCode.FAILED, "第三方接口调用失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 基础响应对象
|
||||
@Data
|
||||
public static class BaseResponse {
|
||||
private String state;
|
||||
private Integer stateCode;
|
||||
private Object outputData;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SmsSendResponse extends BaseResponse {
|
||||
private SmsResult outputData;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SmsResult {
|
||||
private boolean success;
|
||||
private String errMsg;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class LoginResponse extends BaseResponse {
|
||||
private LoginData outputData;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class LoginData {
|
||||
private String idcard_back; // 身份证背面照片地址
|
||||
private String face_img; // 人脸照片地址
|
||||
private String address; // 身份证登记地址
|
||||
private String nation; // 民族(接口文档显示可能为null)
|
||||
private boolean success; // 验证是否成功
|
||||
private String sex; // 性别(男/女)
|
||||
private String name; // 真实姓名
|
||||
private String userid; // 用户在平台的唯一ID
|
||||
private boolean registered; // 是否已注册
|
||||
private String tel; // 手机号码
|
||||
private String idnum; // 身份证号码
|
||||
private String idcard_front; // 身份证正面照片地址
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户退出接口
|
||||
*/
|
||||
public static LogoutResponse doLogout(String token) {
|
||||
String url = BASE_URL + "?code=doLogout";
|
||||
|
||||
Map<String, Object> paramMap = new HashMap<String, Object>() {{
|
||||
put("token", token);
|
||||
}};
|
||||
|
||||
String response = HttpUtil.createPost(url)
|
||||
.body(JSONUtil.toJsonStr(paramMap))
|
||||
.header("noSign", "true")
|
||||
.header("source", "api")
|
||||
.execute().body();
|
||||
log.info("用户退出响应: {}", response);
|
||||
|
||||
LogoutResponse resp = JSONUtil.toBean(response, LogoutResponse.class);
|
||||
checkApiResponse(resp);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class LogoutResponse extends BaseResponse {
|
||||
private LogoutData outputData; // 包含success和logoutTime(登出时间)
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class LogoutData {
|
||||
private boolean success;
|
||||
private String logoutTime;
|
||||
}
|
||||
|
||||
// Token响应对象
|
||||
@Data
|
||||
public static class TokenResponse extends BaseResponse {
|
||||
private TokenData outputData;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class TokenData {
|
||||
private String token;
|
||||
private boolean takeFace;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.agileboot.domain.shop.approval;
|
||||
|
||||
import com.agileboot.common.constant.PayApiConstants;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.shop.approval.command.AddReturnApprovalCommand;
|
||||
|
@ -9,19 +10,31 @@ import com.agileboot.domain.shop.approval.db.ReturnApprovalService;
|
|||
import com.agileboot.domain.shop.approval.dto.ReturnApprovalDTO;
|
||||
import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
|
||||
import com.agileboot.domain.shop.approval.model.ReturnApprovalModelFactory;
|
||||
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
|
||||
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
import com.agileboot.domain.shop.order.model.OrderGoodsModel;
|
||||
import com.agileboot.domain.shop.order.model.OrderGoodsModelFactory;
|
||||
import com.agileboot.domain.shop.order.model.OrderModel;
|
||||
import com.agileboot.domain.shop.order.model.OrderModelFactory;
|
||||
import com.agileboot.domain.shop.payment.PaymentApplicationService;
|
||||
import com.agileboot.domain.shop.payment.dto.RefundVO;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 退货审批应用服务类,处理与退货审批相关的业务逻辑
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
|
@ -30,7 +43,14 @@ public class ReturnApprovalApplicationService {
|
|||
private final ReturnApprovalService approvalService;
|
||||
private final ReturnApprovalModelFactory modelFactory;
|
||||
private final OrderGoodsModelFactory orderGoodsModelFactory;
|
||||
private final OrderModelFactory orderModelFactory;
|
||||
private final PaymentApplicationService paymentApplicationService;
|
||||
|
||||
/**
|
||||
* 获取退货审批列表
|
||||
* @param query 查询条件
|
||||
* @return 分页的退货审批DTO列表
|
||||
*/
|
||||
public PageDTO<ReturnApprovalDTO> getApprovalList(SearchReturnApprovalQuery<ReturnApprovalEntity> query) {
|
||||
Page<ReturnApprovalEntity> page = approvalService.getApprovalList(query);
|
||||
List<ReturnApprovalDTO> dtoList = page.getRecords().stream()
|
||||
|
@ -39,6 +59,11 @@ public class ReturnApprovalApplicationService {
|
|||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加退货审批
|
||||
* @param command 添加退货审批命令
|
||||
* @return 创建的退货审批模型
|
||||
*/
|
||||
public ReturnApprovalModel addApproval(AddReturnApprovalCommand command) {
|
||||
ReturnApprovalModel model = modelFactory.create();
|
||||
model.loadAddCommand(command);
|
||||
|
@ -46,12 +71,20 @@ public class ReturnApprovalApplicationService {
|
|||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新退货审批信息
|
||||
* @param command 更新退货审批命令
|
||||
*/
|
||||
public void updateApproval(UpdateReturnApprovalCommand command) {
|
||||
ReturnApprovalModel model = modelFactory.loadById(command.getApprovalId());
|
||||
model.loadUpdateCommand(command);
|
||||
model.updateById();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除退货审批
|
||||
* @param command 批量操作命令,包含要删除的审批ID列表
|
||||
*/
|
||||
public void deleteApproval(BulkOperationCommand<Long> command) {
|
||||
for (Long approvalId : command.getIds()) {
|
||||
ReturnApprovalModel model = modelFactory.loadById(approvalId);
|
||||
|
@ -59,11 +92,74 @@ public class ReturnApprovalApplicationService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批通过退货申请
|
||||
* @param command 更新退货审批命令
|
||||
* @throws IllegalArgumentException 如果退款金额不合法
|
||||
* @throws RuntimeException 如果退款操作失败
|
||||
*/
|
||||
public void approveApproval(UpdateReturnApprovalCommand command) {
|
||||
ReturnApprovalModel model = modelFactory.loadById(command.getApprovalId());
|
||||
|
||||
|
||||
OrderModel orderModel = orderModelFactory.loadById(model.getOrderId());
|
||||
OrderGoodsModel orderGoodsModel = orderGoodsModelFactory.loadById(model.getOrderGoodsId());
|
||||
// 退款金额对比, 退款金额不能大于订单金额
|
||||
// 金额转换(元转分)并四舍五入
|
||||
BigDecimal amountInFen = orderGoodsModel.getTotalAmount()
|
||||
.multiply(new BigDecimal("100"))
|
||||
.setScale(0, RoundingMode.HALF_UP);
|
||||
BigDecimal returnAmount = command.getReturnAmount();
|
||||
// 退款金额转换(元转分)并四舍五入
|
||||
returnAmount = returnAmount
|
||||
.multiply(new BigDecimal("100"))
|
||||
.setScale(0, RoundingMode.HALF_UP);
|
||||
if (returnAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("退款金额必须大于0");
|
||||
}
|
||||
if (returnAmount.compareTo(amountInFen) > 0) {
|
||||
throw new IllegalArgumentException("退款金额不能超过订单总额");
|
||||
}
|
||||
|
||||
if (!Objects.equals(orderModel.getPaymentMethod(), "balance")) {
|
||||
RefundVO refundVO = null;
|
||||
try {
|
||||
refundVO = paymentApplicationService.refund(
|
||||
PayApiConstants.biz_id, PayApiConstants.appkey,
|
||||
orderModel.getBizOrderId(), orderModel.getUcid(),
|
||||
"退还", returnAmount.intValue());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("退款失败", e);
|
||||
}
|
||||
log.info("退款结果:{}", refundVO);
|
||||
if (null == refundVO || !refundVO.getSuccess()) {
|
||||
throw new RuntimeException("退款失败");
|
||||
}
|
||||
}
|
||||
|
||||
model.validateApprovalStatus();
|
||||
model.setAuditImages(command.getAuditImages());
|
||||
model.setAuditRemark(command.getAuditRemark());
|
||||
model.setReturnAmount(command.getReturnAmount());
|
||||
model.setStatus(2); // 2表示审核通过状态
|
||||
model.updateById();
|
||||
|
||||
// 更新关联订单商品状态
|
||||
orderGoodsModel.setStatus(2); // 6表示已完成退货
|
||||
orderGoodsModel.updateById();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交退货审批申请
|
||||
* @param command 添加退货审批命令
|
||||
* @param orderGoods 关联的订单商品实体
|
||||
* @return 创建的退货审批实体
|
||||
*/
|
||||
public ReturnApprovalEntity submitApproval(AddReturnApprovalCommand command, ShopOrderGoodsEntity orderGoods) {
|
||||
// 设置商品价格并初始化审批状态
|
||||
command.setGoodsId(orderGoods.getGoodsId());
|
||||
command.setOrderId(orderGoods.getOrderId());
|
||||
command.setGoodsPrice(orderGoods.getPrice());
|
||||
command.setGoodsPrice(orderGoods.getTotalAmount());
|
||||
command.setReturnImages(command.getReturnImages());
|
||||
command.setReturnRemark(command.getReturnRemark());
|
||||
command.setStatus(1);
|
||||
|
@ -83,4 +179,24 @@ public class ReturnApprovalApplicationService {
|
|||
|
||||
return returnApprovalModel.selectById();
|
||||
}
|
||||
|
||||
public PageDTO<ReturnApprovalEntity> getApprovalWithGoodsInfo(SearchApiReturnApprovalQuery<ReturnApprovalEntity> query) {
|
||||
Page<ReturnApprovalEntity> page = approvalService.selectApprovalWithGoodsInfo(query);
|
||||
return new PageDTO<>(page.getRecords(), page.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批驳回退货申请
|
||||
* @param command 更新退货审批命令(包含驳回原因)
|
||||
*/
|
||||
public void rejectApproval(UpdateReturnApprovalCommand command) {
|
||||
ReturnApprovalModel model = modelFactory.loadById(command.getApprovalId());
|
||||
model.validateApprovalStatus();
|
||||
|
||||
// 更新审批状态为驳回
|
||||
model.setStatus(3);
|
||||
model.setAuditImages(command.getAuditImages());
|
||||
model.setAuditRemark(command.getAuditRemark());
|
||||
model.updateById();
|
||||
}
|
||||
}
|
|
@ -76,6 +76,14 @@ public class ReturnApprovalEntity extends BaseEntity<ReturnApprovalEntity> {
|
|||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("商品名称")
|
||||
@TableField(exist = false)
|
||||
private String goodsName;
|
||||
|
||||
@ApiModelProperty("封面图URL")
|
||||
@TableField(exist = false)
|
||||
private String coverImg;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
|
|
|
@ -17,6 +17,14 @@ import org.apache.ibatis.annotations.Select;
|
|||
* @since 2025-04-03
|
||||
*/
|
||||
public interface ReturnApprovalMapper extends BaseMapper<ReturnApprovalEntity> {
|
||||
|
||||
@Select("SELECT ra.*, sog.goods_name AS goodsName, sog.cover_img AS coverImg " +
|
||||
"FROM return_approval ra " +
|
||||
"LEFT JOIN shop_order_goods sog ON ra.order_goods_id = sog.order_goods_id " +
|
||||
"${ew.customSqlSegment}")
|
||||
Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(Page<ReturnApprovalEntity> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<ReturnApprovalEntity> queryWrapper);
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM return_approval " +
|
||||
"${ew.customSqlSegment}")
|
||||
|
|
|
@ -21,4 +21,6 @@ public interface ReturnApprovalService extends IService<ReturnApprovalEntity> {
|
|||
List<ReturnApprovalEntity> selectAll();
|
||||
|
||||
ReturnApprovalEntity getByOrderId(Long orderId);
|
||||
|
||||
Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(AbstractPageQuery<ReturnApprovalEntity> query);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.agileboot.domain.shop.approval.db;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
@ -38,4 +39,9 @@ public class ReturnApprovalServiceImpl extends ServiceImpl<ReturnApprovalMapper,
|
|||
.last("LIMIT 1");
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(AbstractPageQuery<ReturnApprovalEntity> query) {
|
||||
return this.baseMapper.selectApprovalWithGoodsInfo(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,4 +36,14 @@ public class ReturnApprovalModel extends ReturnApprovalEntity {
|
|||
loadAddCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateApprovalStatus() {
|
||||
if (getStatus() == null || !isValidStatus(getStatus())) {
|
||||
throw new RuntimeException("审批状态不合法");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidStatus(Integer status) {
|
||||
return !status.equals(2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.agileboot.domain.shop.approval.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SearchApiReturnApprovalQuery<T> extends AbstractPageQuery<T> {
|
||||
|
||||
private Long approvalId;
|
||||
private Long orderId;
|
||||
private Long goodsId;
|
||||
private String goodsName;
|
||||
private Integer status;
|
||||
private String returnRemark;
|
||||
private String auditRemark;
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<T> addQueryCondition() {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper
|
||||
.eq(approvalId != null, "ra.approval_id", approvalId)
|
||||
.eq(orderId != null, "ra.order_id", orderId)
|
||||
.eq(goodsId != null, "ra.goods_id", goodsId)
|
||||
.eq(status != null, "ra.status", status)
|
||||
.like(StrUtil.isNotEmpty(goodsName), "sog.goods_name", goodsName)
|
||||
.between(startTime != null && endTime != null, "ra.create_time", startTime, endTime)
|
||||
.orderByDesc("ra.approval_id");
|
||||
|
||||
this.timeRangeColumn = "create_time";
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
|
@ -127,6 +127,10 @@ public class OrderApplicationService {
|
|||
orderModel.setStatus(1);
|
||||
orderModel.generateOrderNumber();
|
||||
orderModel.setTotalAmount(BigDecimal.valueOf(0));
|
||||
orderModel.setPaymentMethod(command.getPaymentType());
|
||||
orderModel.setMobile(command.getMobile());
|
||||
orderModel.setIsInternal(command.getIsInternal());
|
||||
orderModel.setUserid(command.getQyUserid());
|
||||
orderModel.insert();
|
||||
|
||||
processOrderGoods(orderModel, goodsList);
|
||||
|
@ -169,7 +173,7 @@ public class OrderApplicationService {
|
|||
request.setPay_amount(amountInFen.toPlainString()); // 单位转换为分
|
||||
|
||||
request.setTitle("商品订单支付");
|
||||
request.setNotify_url("http://wxshop.ab98.cn/shop-api/api/payment/callback");
|
||||
request.setNotify_url(PayApiConstants.pay_callback_url);
|
||||
request.setBiz_id(PayApiConstants.biz_id);
|
||||
request.setUcid(orderModel.getUcid());
|
||||
request.setExtra("");
|
||||
|
|
|
@ -3,15 +3,34 @@ package com.agileboot.domain.shop.order.command;
|
|||
import com.agileboot.domain.shop.order.db.ShopOrderEntity;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SubmitOrderCommand {
|
||||
@ApiModelProperty("微信用户唯一标识")
|
||||
private String openid;
|
||||
@ApiModelProperty("系统用户ID")
|
||||
private String userid;
|
||||
@ApiModelProperty("企业ID")
|
||||
private String corpid;
|
||||
@ApiModelProperty("订单主体信息")
|
||||
private ShopOrderEntity order;
|
||||
// 支付类型'wechat' | 'balance'
|
||||
|
||||
@ApiModelProperty("支付类型 wechat:微信 balance:余额")
|
||||
private String paymentType;
|
||||
|
||||
@ApiModelProperty("订单商品明细列表")
|
||||
private List<ShopOrderGoodsEntity> goodsList;
|
||||
|
||||
@ApiModelProperty("联系电话")
|
||||
private String mobile;
|
||||
|
||||
@ApiModelProperty("企业微信用户ID或汇邦云用户ID")
|
||||
private String qyUserid;
|
||||
|
||||
@ApiModelProperty("是否内部订单 0否 1汇邦云用户 2企业微信用户")
|
||||
private Integer isInternal;
|
||||
}
|
|
@ -45,6 +45,18 @@ public class ShopOrderEntity extends BaseEntity<ShopOrderEntity> {
|
|||
@TableField("trade_id")
|
||||
private String tradeId;
|
||||
|
||||
@ApiModelProperty("手机号码")
|
||||
@TableField("mobile")
|
||||
private String mobile;
|
||||
|
||||
@ApiModelProperty("企业微信用户ID或汇邦云用户ID")
|
||||
@TableField("userid")
|
||||
private String userid;
|
||||
|
||||
@ApiModelProperty("是否内部用户(0否 1汇邦云用户 2企业微信用户)")
|
||||
@TableField("is_internal")
|
||||
private Integer isInternal;
|
||||
|
||||
@ApiModelProperty("业务系统订单ID(对接外部系统)")
|
||||
@TableField("biz_order_id")
|
||||
private String bizOrderId;
|
||||
|
|
|
@ -52,6 +52,14 @@ public class ShopOrderGoodsEntity extends BaseEntity<ShopOrderGoodsEntity> {
|
|||
@TableField("total_amount")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@ApiModelProperty("商品名称")
|
||||
@TableField("goods_name")
|
||||
private String goodsName;
|
||||
|
||||
@ApiModelProperty("封面图URL")
|
||||
@TableField("cover_img")
|
||||
private String coverImg;
|
||||
|
||||
@ApiModelProperty("商品状态(1正常 2已退货 3已换货 4已完成 5审核中 6退货未通过)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package com.agileboot.domain.shop.order.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderEntity;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ApiModel(value = "ShopOrderDTO对象", description = "商品订单DTO")
|
||||
public class ShopOrderDTO {
|
||||
|
||||
public ShopOrderDTO(ShopOrderEntity entity) {
|
||||
|
@ -23,14 +27,29 @@ public class ShopOrderDTO {
|
|||
}
|
||||
}
|
||||
|
||||
@ApiModelProperty("订单唯一ID")
|
||||
private Long orderId;
|
||||
@ApiModelProperty("ucid")
|
||||
private String ucid;
|
||||
@ApiModelProperty("openid")
|
||||
private String openid;
|
||||
@ApiModelProperty("支付网关交易id")
|
||||
private String tradeId;
|
||||
@ApiModelProperty("订单总金额")
|
||||
private BigDecimal totalAmount;
|
||||
@ApiModelProperty("订单状态(1待付款 2已付款 3已发货 4已完成 5已取消)")
|
||||
private Integer status;
|
||||
@ApiModelProperty("支付状态(1未支付 2已支付 3退款中 4已退款)")
|
||||
private Integer payStatus;
|
||||
@ApiModelProperty("支付方式")
|
||||
private String paymentMethod;
|
||||
@ApiModelProperty("支付时间")
|
||||
private Date payTime;
|
||||
private Date createTime;
|
||||
@ApiModelProperty("手机号码")
|
||||
private String mobile;
|
||||
@ApiModelProperty("是否内部用户(0否 1是)")
|
||||
private Integer isInternal;
|
||||
@ApiModelProperty("业务系统订单ID(对接外部系统)")
|
||||
private String bizOrderId;
|
||||
}
|
|
@ -35,6 +35,8 @@ public class OrderGoodsModel extends ShopOrderGoodsEntity {
|
|||
ShopGoodsEntity goods = goodsService.getById(getGoodsId());
|
||||
if (goods != null) {
|
||||
BigDecimal price = goods.getPrice();
|
||||
this.setGoodsName(goods.getGoodsName());
|
||||
this.setCoverImg(goods.getCoverImg());
|
||||
this.setPrice(price);
|
||||
this.setTotalAmount(price.multiply(BigDecimal.valueOf(getQuantity())));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.agileboot.domain.shop.order.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.shop.goods.db.ShopGoodsService;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsService;
|
||||
|
@ -13,6 +15,14 @@ public class OrderGoodsModelFactory {
|
|||
private final ShopOrderGoodsService orderGoodsService;
|
||||
private final ShopGoodsService goodsService;
|
||||
|
||||
public OrderGoodsModel loadById(Long orderGoodsId) {
|
||||
ShopOrderGoodsEntity entity = orderGoodsService.getById(orderGoodsId);
|
||||
if (entity == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, orderGoodsId, "订单商品");
|
||||
}
|
||||
return new OrderGoodsModel(entity, orderGoodsService, goodsService);
|
||||
}
|
||||
|
||||
public OrderGoodsModel create(ShopOrderGoodsEntity entity) {
|
||||
return new OrderGoodsModel(entity, orderGoodsService, goodsService);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -34,7 +35,7 @@ public class PaymentApplicationService {
|
|||
private static final Object LOCKER = new Object();
|
||||
|
||||
public WxJsApiPreCreateResponse callJsApiPreCreate(WxJsApiPreCreateRequest request) {
|
||||
String gatewayUrl = "http://222.218.10.217:7890/open/trade/wx/jsapi/precreate";
|
||||
String gatewayUrl = PayApiConstants.pay_url;
|
||||
|
||||
try {
|
||||
String jsonBody = JSONUtil.toJsonStr(request);
|
||||
|
@ -115,7 +116,7 @@ public class PaymentApplicationService {
|
|||
* @param money 退款金额,单位:分
|
||||
*/
|
||||
public RefundVO refund(String bizId, String appKey, String orderId, String uid, String reason, int money) throws Exception {
|
||||
String url = "http://222.218.10.217:7890/open/trade/refund";
|
||||
String url = PayApiConstants.refund_url;
|
||||
JSONObject bizContent = new JSONObject();
|
||||
bizContent.set("userId", uid);
|
||||
bizContent.set("bizId", bizId);
|
||||
|
@ -129,7 +130,8 @@ public class PaymentApplicationService {
|
|||
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
||||
params.put("version", "1.0");
|
||||
params.put("nonce_str", UUID.randomUUID().toString());
|
||||
params.put("biz_content", URLUtil.encode(JSONUtil.toJsonStr(bizContent)));
|
||||
params.put("biz_content", URLEncoder.encode(JSONUtil.toJsonStr(bizContent), StandardCharsets.UTF_8.name()));
|
||||
log.info("退款请求参数:{}", JSONUtil.toJsonStr(params));
|
||||
params.put("sign", SignUtils.openSign(appKey, params));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String key : params.keySet()) {
|
||||
|
@ -202,8 +204,8 @@ public class PaymentApplicationService {
|
|||
|
||||
String orderNO = bizContent.getBizOrderId();
|
||||
if (StringUtils.isBlank(orderNO)) {
|
||||
res.put("callback_code", 1);
|
||||
res.put("callback_msg", "缺少退款订单ID");
|
||||
res.set("callback_code", 1);
|
||||
res.set("callback_msg", "缺少退款订单ID");
|
||||
return JSONUtil.toJsonStr(res);
|
||||
}
|
||||
synchronized (LOCKER) {
|
||||
|
@ -212,8 +214,9 @@ public class PaymentApplicationService {
|
|||
if (orderNO.startsWith("wxshop-")) {
|
||||
// 订单号格式为 wxshop-1-time,提取中间的订单号
|
||||
String orderId = orderNO.split("-")[1];
|
||||
OrderModel orderModel = orderModelFactory.loadById(Long.valueOf(orderId));
|
||||
orderModel.handleRefundSuccess();
|
||||
log.info("退款回调处理成功, 订单号:{}", orderId);
|
||||
// OrderModel orderModel = orderModelFactory.loadById(Long.valueOf(orderId));
|
||||
// orderModel.handleRefundSuccess();
|
||||
}
|
||||
}
|
||||
res.set("callback_code", 0);
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
## 请求概述
|
||||
### 请求header
|
||||
所有请求必须包含以下两个header:
|
||||
* `noSign`: `true`
|
||||
* `source`: `api`
|
||||
获取登录token后,也可以在header中添加:
|
||||
* `token`: `${token}`
|
||||
### 登录校验结果
|
||||
接口返回结果为json格式,如果包含`code`字段,则说明登录校验失败。
|
||||
* `code`: `0001` - 登录状态已失效
|
||||
* `code`: `0002` - 在cookie、Get参数、Header中均未检测到token
|
||||
## 登录接口
|
||||
### 2.1 获取token
|
||||
* **API**: `https://www.ab98.cn/api/doInterface?code=doGetToken&from=jt&app=${appname}`
|
||||
* **请求方式**: GET
|
||||
* **请求参数**:
|
||||
* `code`: `doGetToken` (必传)
|
||||
* `from`: `jt` (可选)
|
||||
* `app`: 调用该接口的应用在汇邦数字平台登记的应用英文名 (可选)
|
||||
**成功返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": {
|
||||
"token": "1a6ea39e84c406283839856640e3aa66",
|
||||
"takeFace": true
|
||||
},
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
||||
**失败返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": "错误信息",
|
||||
"stateCode": 0,
|
||||
"state": "fail"
|
||||
}
|
||||
```
|
||||
### 2.2 短信登录
|
||||
#### 2.2.1 发送短信
|
||||
* **API**: `https://www.ab98.cn/api/doInterface?code=doSendSms`
|
||||
* **请求方式**: POST
|
||||
* **Content-Type**: application/json
|
||||
* **请求BODY**:
|
||||
```json
|
||||
{
|
||||
"token":"358900e1005c33a1dd059b07042ceec3", //必传
|
||||
"tel":"137xxxxxxxx", //必传
|
||||
"nobind":"true", //必传
|
||||
"for_login":"true", //必传
|
||||
"from":"jt" //必传
|
||||
}
|
||||
```
|
||||
**成功返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": {
|
||||
"success": true
|
||||
},
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
||||
**失败返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": {
|
||||
"success": false,
|
||||
"errMsg": "失败原因"
|
||||
},
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
||||
#### 2.2.2 验证短信验证码
|
||||
* **API**: `https://www.ab98.cn/api/doInterface?code=doCheckSmsCode`
|
||||
* **请求方式**: POST
|
||||
* **Content-Type**: application/json
|
||||
* **请求BODY**:
|
||||
```json
|
||||
{
|
||||
"token":"358900e1005c33a1dd059b07042ceec3",
|
||||
"tel":"137xxxxxxxx",
|
||||
"vcode":"123456"
|
||||
}
|
||||
```
|
||||
**成功返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": {
|
||||
"idcard_back": "https://www.ab98.cn/upload/temp/images/202102/xxx.jpeg",
|
||||
"face_img": "https://www.ab98.cn/upload/temp/images/202102/yyy.jpeg",
|
||||
"address": "身份证上的地址",
|
||||
"nation": null,
|
||||
"success": true,
|
||||
"sex": "男",
|
||||
"name": "xxx",
|
||||
"userid": 123,
|
||||
"registered": true,
|
||||
"tel": "137xxxxxxxx",
|
||||
"idnum": "450981xxxxxxxxxxxx",
|
||||
"idcard_front": "https://www.ab98.cn/upload/temp/images/202102/zzz.jpeg"
|
||||
},
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
||||
**失败返回**:
|
||||
```json
|
||||
{
|
||||
"outputData": {
|
||||
"success": false
|
||||
},
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
||||
### 2.3 微信扫码登录
|
||||
* **API**: `https://www.ab98.cn/online/index.html?content=doLogin%60`
|
||||
#### 2.3.1 二维码
|
||||
假设获取到的token为`358900e1005c33a1dd059b07042ceec3`,则构造的最终链接为:
|
||||
`https://www.ab98.cn/online/index.html?content=doLogin%60358900e1005c33a1dd059b07042ceec3`
|
||||
使用该链接生成二维码图片供用户使用微信“扫一扫”。
|
||||
#### 2.3.2 监听websocket
|
||||
* **监听地址**: `wss://www.ab98.cn/login.ws/${token}`
|
||||
* **登录失败**:
|
||||
```json
|
||||
{
|
||||
"outputData": "登录失败原因",
|
||||
"state": "fail"
|
||||
}
|
||||
```
|
||||
* **登录成功**:
|
||||
```json
|
||||
{
|
||||
"outputData": "登录成功",
|
||||
"state": "ok",
|
||||
"username": "扫码者姓名",
|
||||
"sex": "扫码者性别",
|
||||
"head_img": "扫码者头像",
|
||||
"idnum": "身份证号码",
|
||||
"userid": "人员记录ID",
|
||||
"tel": "手机号码"
|
||||
}
|
||||
```
|
||||
### 2.4 刷脸登录
|
||||
* **API**: `https://www.ab98.cn/api/doInterface?code=doStrongFaceLogin`
|
||||
* **请求方式**: POST
|
||||
* **Content-Type**: application/json
|
||||
* **请求BODY**:
|
||||
```json
|
||||
{
|
||||
"token":"358900e1005c33a1dd059b07042ceec3", //必传
|
||||
"check_code":"1234", //必传
|
||||
"imgBase64":"/9j/4AAQS…" //必传
|
||||
}
|
||||
```
|
||||
**成功返回**:
|
||||
```json
|
||||
{
|
||||
"state": "ok",
|
||||
"outputData": "登录成功",
|
||||
"openid": "oGfFD1jBEZ2sq4PhOc8zKKejHA9E",
|
||||
"head_img": "https://www.ab98.cn/… ",
|
||||
"sex": "男",
|
||||
"userid": 1,
|
||||
"token": "dbe11ef64cd6350c5d935d531db765c0",
|
||||
"username": "xxx",
|
||||
"tel": "xxx"
|
||||
}
|
||||
```
|
||||
### 2.5 动态码登录
|
||||
1. **发起websocket监听**:
|
||||
`wss://www.ab98.cn/login.ws/{监听token}`
|
||||
其中 `{监听token}` 由客户端自定义,由数字和英文字母组成,保证多用户同时监听时 `{监听token}` 互不相同即可,否则会接收到错误消息。
|
||||
2. **主动发送消息**:
|
||||
```json
|
||||
{
|
||||
"type": "mfa",
|
||||
"do": "checkCode",
|
||||
"token": "xxx",
|
||||
"code": "000000"
|
||||
}
|
||||
```
|
||||
**服务器响应消息**:
|
||||
1. **登录失败**:
|
||||
```json
|
||||
{
|
||||
"state": "fail",
|
||||
"msg": "失败原因"
|
||||
}
|
||||
```
|
||||
2. **动态码校验通过,等待移动端授权登录**:
|
||||
```json
|
||||
{
|
||||
"state": "ok",
|
||||
"step": "0"
|
||||
}
|
||||
```
|
||||
3. **等待移动端授权超时**:
|
||||
```json
|
||||
{
|
||||
"state": "ok",
|
||||
"step": "1"
|
||||
}
|
||||
```
|
||||
4. **移动端已授权登录**:
|
||||
```json
|
||||
{
|
||||
"state": "ok",
|
||||
"step": "2",
|
||||
"openid": "xxx",
|
||||
"head_img": "/xxx",
|
||||
"sex": "男/女",
|
||||
"company": "xxx",
|
||||
"userid": 123,
|
||||
"idnum": "xxx",
|
||||
"username": "xxx",
|
||||
"tel": "xxx"
|
||||
}
|
||||
```
|
||||
### 2.6 退出登录
|
||||
* **API**: `https://www.ab98.cn/api/doInterface?code=doLogout`
|
||||
* **请求方式**: POST
|
||||
* **Content-Type**: application/json
|
||||
* **请求BODY**:
|
||||
```json
|
||||
{
|
||||
"token":"358900e1005c33a1dd059b07042ceec3"
|
||||
}
|
||||
```
|
||||
**成功返回**:
|
||||
```json
|
||||
{
|
||||
"state": "ok"
|
||||
}
|
||||
```
|
|
@ -49,4 +49,20 @@ ALTER TABLE `return_approval`
|
|||
ADD CONSTRAINT `fk_return_order_goods` FOREIGN KEY (`order_goods_id`) REFERENCES `shop_order_goods` (`order_goods_id`);
|
||||
|
||||
ALTER TABLE `shop_order`
|
||||
ADD COLUMN `biz_order_id` VARCHAR(32) NULL COMMENT '业务系统订单ID(对接外部系统)' AFTER `trade_id`;
|
||||
ADD COLUMN `biz_order_id` VARCHAR(32) NULL COMMENT '业务系统订单ID(对接外部系统)' AFTER `trade_id`;
|
||||
|
||||
ALTER TABLE shop_order_goods
|
||||
ADD COLUMN goods_name VARCHAR(255) NOT NULL COMMENT '商品名称',
|
||||
ADD COLUMN cover_img VARCHAR(512) COMMENT '封面图URL';
|
||||
|
||||
UPDATE shop_order_goods sog
|
||||
INNER JOIN shop_goods sg ON sog.goods_id = sg.goods_id
|
||||
SET sog.goods_name = sg.goods_name,
|
||||
sog.cover_img = sg.cover_img;
|
||||
|
||||
ALTER TABLE `shop_order`
|
||||
ADD COLUMN `mobile` varchar(30) DEFAULT NULL COMMENT '手机号码' AFTER `trade_id`,
|
||||
ADD COLUMN `is_internal` TINYINT(1) DEFAULT 0 COMMENT '是否内部用户(0否 1是)';
|
||||
|
||||
ALTER TABLE `shop_order`
|
||||
ADD COLUMN `userid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '企业微信用户ID或汇邦云用户ID' AFTER `mobile`;
|
||||
|
|
Loading…
Reference in New Issue