Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
842a425c
authored
Oct 28, 2025
by
Jony.L
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
新支付功能测试6.0,继续回调测试
parent
fa76472d
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1329 additions
and
898 deletions
+1329
-898
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/notify/ComputeWpgjPayController.java
+181
-0
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/ResourceOrderController.java
+3
-150
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/vo/WpgjPayNotifyDTO.java
+0
-84
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/vo/WpgjPayNotifyRespDTO.java
+0
-24
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/app/resourceorder/AppResourceOrderController.java
+3
-3
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/app/resourceorder/vo/AppWpgjPayOrderSubmitRespVO.java
+33
-0
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/dal/mysql/resourceorder/ResourceOrderMapper.java
+7
-0
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/service/resourceorder/ResourceOrderService.java
+29
-3
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/service/resourceorder/ResourceOrderServiceImpl.java
+172
-68
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApi.java
+10
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApiImpl.java
+183
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/dto/WpgjPayOrderRespDTO.java
+44
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/PayOrderWpgjApi.java
+22
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/PayOrderWpgjApiImpl.java
+71
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/dto/PayOrderWpgjCreateReqDTO.java
+48
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/vo/WpgjPayOrderSubmitReqVO.java
+23
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/admin/notify/WpgjPayController.java
+0
-202
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/AppPayOrderController.java
+17
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java
+3
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/vo/PayOrderWpgjRespVO.java
+90
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/dal/dataobject/wpgj/PayOrderWpgjDO.java
+134
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/dal/mysql/wpgj/PayOrderWpgjMapper.java
+29
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/enums/WpgjOrderStatusEnum.java
+1
-1
computility-module-pay/src/main/java/com/luhu/computility/module/pay/enums/order/WpgjOrderStatusEnum.java
+0
-50
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/dto/order/WpgjBusinessDataDTO.java
+42
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/dto/order/WpgjUnifiedOrderReqDTO.java
+43
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/order/PayOrderService.java
+1
-11
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/order/PayOrderServiceImpl.java
+13
-302
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/wpgj/PayOrderWpgjService.java
+46
-0
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/wpgj/PayOrderWpgjServiceImpl.java
+81
-0
No files found.
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/notify/ComputeWpgjPayController.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
compute
.
controller
.
admin
.
notify
;
import
cn.hutool.core.util.StrUtil
;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyRespDTO
;
import
com.luhu.computility.module.compute.service.resourceorder.ResourceOrderService
;
import
com.luhu.computility.module.pay.enums.WpgjOrderStatusEnum
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
javax.annotation.Resource
;
import
javax.annotation.security.PermitAll
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.crypto.digest.DigestUtil
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
/**
* 算力资源模块 - WPGJ旺铺聚合支付回调Controller
*
* 独立处理WPGJ支付回调,直接更新算力资源订单状态
*
* @author jony
*/
@Tag
(
name
=
"管理后台 - 算力资源WPGJ旺铺聚合支付回调"
)
@RestController
@RequestMapping
(
"/compute/wpgj"
)
@Slf4j
public
class
ComputeWpgjPayController
{
@Resource
private
ResourceOrderService
resourceOrderService
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@PostMapping
(
"/notify"
)
@PermitAll
@Operation
(
summary
=
"WPGJ支付异步回调通知 - 算力资源模块"
)
public
CommonResult
<
WpgjPayNotifyRespDTO
>
notifyWpgjPay
(
@RequestBody
WpgjPayNotifyDTO
notifyDTO
)
{
WpgjPayNotifyRespDTO
response
=
new
WpgjPayNotifyRespDTO
();
try
{
log
.
info
(
"[notifyWpgjPay][Compute] 收到WPGJ支付回调: {}"
,
JsonUtils
.
toJsonString
(
notifyDTO
));
// 1. 验证签名
if
(!
verifyWpgjSignature
(
notifyDTO
))
{
log
.
error
(
"[notifyWpgjPay][Compute] WPGJ回调签名验证失败"
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"签名验证失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
CommonResult
.
success
(
response
);
}
// 2. 处理支付结果通知
handleWpgjPaymentResult
(
notifyDTO
);
log
.
info
(
"[notifyWpgjPay][Compute] WPGJ支付回调处理完成"
);
response
.
setCode
(
"00"
);
response
.
setMsg
(
"成功"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
CommonResult
.
success
(
response
);
}
catch
(
Exception
e
)
{
log
.
error
(
"[notifyWpgjPay][Compute] WPGJ支付回调处理失败"
,
e
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"处理失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
CommonResult
.
success
(
response
);
}
}
/**
* 处理WPGJ支付结果
*/
private
void
handleWpgjPaymentResult
(
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
String
merOrderId
=
notifyDTO
.
getMerOrderId
();
String
orderStatus
=
notifyDTO
.
getOrderStatus
();
log
.
info
(
"[handleWpgjPaymentResult] 处理WPGJ支付结果,商户订单号: {}, 订单状态: {}"
,
merOrderId
,
orderStatus
);
// 根据WPGJ订单状态更新算力资源订单
if
(
WpgjOrderStatusEnum
.
isSuccess
(
orderStatus
))
{
// 支付成功
resourceOrderService
.
updateOrderPaidByWpgj
(
Long
.
parseLong
(
merOrderId
),
notifyDTO
);
log
.
info
(
"[handleWpgjPaymentResult] 算力资源订单支付成功处理完成,商户订单号: {}"
,
merOrderId
);
}
else
if
(
WpgjOrderStatusEnum
.
isFailedOrClosed
(
orderStatus
))
{
// 支付失败或关闭
resourceOrderService
.
updateOrderFailedByWpgj
(
Long
.
parseLong
(
merOrderId
),
notifyDTO
);
log
.
info
(
"[handleWpgjPaymentResult] 算力资源订单支付失败处理完成,商户订单号: {}"
,
merOrderId
);
}
else
{
// 其他状态(处理中等),暂不处理
log
.
info
(
"[handleWpgjPaymentResult] WPGJ订单状态无需处理,商户订单号: {}, 状态: {}"
,
merOrderId
,
orderStatus
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"[handleWpgjPaymentResult] 处理WPGJ支付结果异常"
,
e
);
throw
e
;
}
}
/**
* 验证WPGJ回调签名
*/
private
boolean
verifyWpgjSignature
(
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
// 1. 构建待签名字符串
StringBuilder
sb
=
new
StringBuilder
();
// 按照字段名ASCII码排序拼接
sb
.
append
(
"device_no="
).
append
(
notifyDTO
.
getDeviceNo
());
sb
.
append
(
"&mer_no="
).
append
(
notifyDTO
.
getMerNo
());
sb
.
append
(
"&payway_code="
).
append
(
notifyDTO
.
getPaywayCode
());
sb
.
append
(
"&order_id="
).
append
(
notifyDTO
.
getOrderId
());
sb
.
append
(
"&mer_order_id="
).
append
(
notifyDTO
.
getMerOrderId
());
sb
.
append
(
"&order_time="
).
append
(
notifyDTO
.
getOrderTime
());
sb
.
append
(
"&order_amt="
).
append
(
notifyDTO
.
getOrderAmt
());
sb
.
append
(
"&order_status="
).
append
(
notifyDTO
.
getOrderStatus
());
// 可选字段(非空才加入)
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getMerCode
()))
{
sb
.
append
(
"&mer_code="
).
append
(
notifyDTO
.
getMerCode
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getGatewayMerOrderId
()))
{
sb
.
append
(
"&gateway_mer_order_id="
).
append
(
notifyDTO
.
getGatewayMerOrderId
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeNo
()))
{
sb
.
append
(
"&trade_no="
).
append
(
notifyDTO
.
getTradeNo
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeTime
()))
{
sb
.
append
(
"&trade_time="
).
append
(
notifyDTO
.
getTradeTime
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getOrderTitle
()))
{
sb
.
append
(
"&order_title="
).
append
(
notifyDTO
.
getOrderTitle
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getFee
()))
{
sb
.
append
(
"&fee="
).
append
(
notifyDTO
.
getFee
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getActAmt
()))
{
sb
.
append
(
"&act_amt="
).
append
(
notifyDTO
.
getActAmt
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getBuyerId
()))
{
sb
.
append
(
"&buyer_id="
).
append
(
notifyDTO
.
getBuyerId
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeTopNo
()))
{
sb
.
append
(
"&trade_top_no="
).
append
(
notifyDTO
.
getTradeTopNo
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getCardType
()))
{
sb
.
append
(
"&card_type="
).
append
(
notifyDTO
.
getCardType
());
}
// 2. 添加key
sb
.
append
(
"&key="
).
append
(
wpgjPayProperties
.
getSignKey
());
// 3. 计算MD5签名
String
signStr
=
sb
.
toString
();
String
calculatedSign
=
DigestUtil
.
md5Hex
(
signStr
).
toUpperCase
();
log
.
info
(
"[verifyWpgjSignature][Compute] 待签名字符串: {}"
,
signStr
);
log
.
info
(
"[verifyWpgjSignature][Compute] 计算签名: {}"
,
calculatedSign
);
log
.
info
(
"[verifyWpgjSignature][Compute] 原始签名: {}"
,
notifyDTO
.
getSign
());
// 4. 验证签名
return
calculatedSign
.
equals
(
notifyDTO
.
getSign
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[verifyWpgjSignature][Compute] WPGJ签名验证异常"
,
e
);
return
false
;
}
}
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/ResourceOrderController.java
View file @
842a425c
...
@@ -6,11 +6,7 @@ import com.luhu.computility.framework.common.exception.ServiceException;
...
@@ -6,11 +6,7 @@ import com.luhu.computility.framework.common.exception.ServiceException;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.WpgjPayNotifyRespDTO
;
import
com.luhu.computility.module.compute.enums.WpgjOrderStatusEnum
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.*
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.*
;
import
com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus
;
import
com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus
;
...
@@ -57,9 +53,7 @@ public class ResourceOrderController {
...
@@ -57,9 +53,7 @@ public class ResourceOrderController {
@Resource
@Resource
private
PayOrderService
payOrderService
;
private
PayOrderService
payOrderService
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
/**
/**
* 内部支付任务回调
* 内部支付任务回调
*/
*/
...
@@ -72,149 +66,8 @@ public class ResourceOrderController {
...
@@ -72,149 +66,8 @@ public class ResourceOrderController {
return
success
(
true
);
return
success
(
true
);
}
}
/**
* WPGJ旺铺聚合支付回调通知
*/
@PostMapping
(
"/pay/wpgj-notify"
)
@PermitAll
@TenantIgnore
@Operation
(
summary
=
"WPGJ支付异步回调通知"
)
public
WpgjPayNotifyRespDTO
notifyWpgjPay
(
@RequestBody
WpgjPayNotifyDTO
notifyDTO
)
{
WpgjPayNotifyRespDTO
response
=
new
WpgjPayNotifyRespDTO
();
try
{
log
.
info
(
"[notifyWpgjPay] 收到WPGJ支付回调: {}"
,
JsonUtils
.
toJsonString
(
notifyDTO
));
// 1. 验证签名
if
(!
verifyWpgjSignature
(
notifyDTO
))
{
log
.
error
(
"[notifyWpgjPay] WPGJ回调签名验证失败"
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"签名验证失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
// 2. 解析回调数据,构造PayOrderRespDTO
PayOrderRespDTO
notify
=
parseWpgjNotifyData
(
notifyDTO
);
// 3. 处理支付结果通知
// 由于WPGJ是特殊渠道,直接调用内部处理方法
payOrderService
.
notifyOrder
(-
1L
,
notify
);
// 使用-1表示WPGJ特殊渠道
log
.
info
(
"[notifyWpgjPay] WPGJ支付回调处理完成"
);
response
.
setCode
(
"00"
);
response
.
setMsg
(
"成功"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
catch
(
Exception
e
)
{
log
.
error
(
"[notifyWpgjPay] WPGJ支付回调处理失败"
,
e
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"处理失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
}
/**
* 验证WPGJ回调签名
*/
private
boolean
verifyWpgjSignature
(
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
// 1. 构建待签名字符串 - 按照WPGJ文档要求的ASCII码排序
StringBuilder
sb
=
new
StringBuilder
();
// 严格按照ASCII码排序的所有参数
appendParam
(
sb
,
"act_amt"
,
notifyDTO
.
getActAmt
());
appendParam
(
sb
,
"buyer_id"
,
notifyDTO
.
getBuyerId
());
appendParam
(
sb
,
"card_type"
,
notifyDTO
.
getCardType
());
appendParam
(
sb
,
"device_no"
,
notifyDTO
.
getDeviceNo
());
appendParam
(
sb
,
"fee"
,
notifyDTO
.
getFee
());
appendParam
(
sb
,
"gateway_mer_order_id"
,
notifyDTO
.
getGatewayMerOrderId
());
appendParam
(
sb
,
"mer_code"
,
notifyDTO
.
getMerCode
());
appendParam
(
sb
,
"mer_no"
,
notifyDTO
.
getMerNo
());
appendParam
(
sb
,
"mer_order_id"
,
notifyDTO
.
getMerOrderId
());
appendParam
(
sb
,
"order_amt"
,
notifyDTO
.
getOrderAmt
());
appendParam
(
sb
,
"order_id"
,
notifyDTO
.
getOrderId
());
appendParam
(
sb
,
"order_status"
,
notifyDTO
.
getOrderStatus
());
appendParam
(
sb
,
"order_time"
,
notifyDTO
.
getOrderTime
());
appendParam
(
sb
,
"order_title"
,
notifyDTO
.
getOrderTitle
());
appendParam
(
sb
,
"payway_code"
,
notifyDTO
.
getPaywayCode
());
appendParam
(
sb
,
"trade_no"
,
notifyDTO
.
getTradeNo
());
appendParam
(
sb
,
"trade_time"
,
notifyDTO
.
getTradeTime
());
appendParam
(
sb
,
"trade_top_no"
,
notifyDTO
.
getTradeTopNo
());
// 3. 添加key
String
signKey
=
wpgjPayProperties
.
getSignKey
();
// 签名密钥
sb
.
append
(
"&key="
).
append
(
signKey
);
// 4. 计算MD5签名
String
signStr
=
sb
.
toString
();
String
calculatedSign
=
cn
.
hutool
.
crypto
.
digest
.
DigestUtil
.
md5Hex
(
signStr
).
toUpperCase
();
log
.
info
(
"[verifyWpgjSignature] 待签名字符串: {}"
,
signStr
);
log
.
info
(
"[verifyWpgjSignature] 计算签名: {}"
,
calculatedSign
);
log
.
info
(
"[verifyWpgjSignature] 原始签名: {}"
,
notifyDTO
.
getSign
());
// 5. 验证签名
return
calculatedSign
.
equals
(
notifyDTO
.
getSign
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[verifyWpgjSignature] 签名验证异常"
,
e
);
return
false
;
}
}
/**
* 追加参数到签名字符串
*/
private
void
appendParam
(
StringBuilder
sb
,
String
key
,
String
value
)
{
if
(
StrUtil
.
isNotBlank
(
value
))
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
"&"
);
}
sb
.
append
(
key
).
append
(
"="
).
append
(
value
);
}
}
/**
* 解析WPGJ回调数据为PayOrderRespDTO
*/
private
PayOrderRespDTO
parseWpgjNotifyData
(
WpgjPayNotifyDTO
notifyDTO
)
{
PayOrderRespDTO
notify
=
new
PayOrderRespDTO
();
// 根据WPGJ回调文档解析字段
notify
.
setOutTradeNo
(
notifyDTO
.
getMerOrderId
());
// 商户订单号
notify
.
setChannelOrderNo
(
notifyDTO
.
getTradeNo
());
// 第三方交易号
notify
.
setStatus
(
parseWpgjStatus
(
notifyDTO
.
getOrderStatus
()));
// 交易状态
// 设置支付成功时间
if
(
WpgjOrderStatusEnum
.
isSuccess
(
notifyDTO
.
getOrderStatus
()))
{
notify
.
setSuccessTime
(
java
.
time
.
LocalDateTime
.
now
());
}
// 设置其他必要的字段
notify
.
setChannelCode
(
"wpgj_dynamic"
);
notify
.
setChannelErrorCode
(
null
);
// 成功时没有错误码
notify
.
setChannelErrorMsg
(
null
);
notify
.
setRawData
(
JsonUtils
.
toJsonString
(
notifyDTO
));
// 保存原始数据
return
notify
;
}
/**
* 解析WPGJ交易状态
*/
private
Integer
parseWpgjStatus
(
String
orderStatus
)
{
if
(
WpgjOrderStatusEnum
.
isSuccess
(
orderStatus
))
{
// 1-成功
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
SUCCESS
.
getStatus
();
}
else
if
(
WpgjOrderStatusEnum
.
isFailedOrClosed
(
orderStatus
))
{
// 0-处理中 2-失败
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
CLOSED
.
getStatus
();
}
else
{
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
WAITING
.
getStatus
();
}
}
@PostMapping
(
"/create"
)
@PostMapping
(
"/create"
)
@Operation
(
summary
=
"创建算力资源订单"
)
@Operation
(
summary
=
"创建算力资源订单"
)
@PreAuthorize
(
"@ss.hasPermission('compute:resource-order:create')"
)
@PreAuthorize
(
"@ss.hasPermission('compute:resource-order:create')"
)
...
...
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/vo/WpgjPayNotifyDTO.java
deleted
100644 → 0
View file @
fa76472d
package
com
.
luhu
.
computility
.
module
.
compute
.
controller
.
admin
.
resourceorder
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
javax.validation.constraints.NotBlank
;
/**
* WPGJ旺铺聚合支付回调DTO
*
* @author jonyl
*/
@Schema
(
description
=
"WPGJ旺铺聚合支付回调DTO"
)
@Data
public
class
WpgjPayNotifyDTO
{
@Schema
(
description
=
"旺铺平台唯一设备SN号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"设备编号不能为空"
)
private
String
deviceNo
;
@Schema
(
description
=
"内部商户号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"商户号不能为空"
)
private
String
merNo
;
@Schema
(
description
=
"商户代码"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"商户代码不能为空"
)
private
String
merCode
;
@Schema
(
description
=
"支付通道代码"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"支付通道代码不能为空"
)
private
String
paywayCode
;
@Schema
(
description
=
"旺铺订单号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"旺铺订单号不能为空"
)
private
String
orderId
;
@Schema
(
description
=
"商户订单id,系统唯一"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"商户订单号不能为空"
)
private
String
merOrderId
;
@Schema
(
description
=
"网关商户订单号"
)
private
String
gatewayMerOrderId
;
@Schema
(
description
=
"下单时间"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"下单时间不能为空"
)
private
String
orderTime
;
@Schema
(
description
=
"订单金额"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"订单金额不能为空"
)
private
String
orderAmt
;
@Schema
(
description
=
"订单状态"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"订单状态不能为空"
)
private
String
orderStatus
;
@Schema
(
description
=
"通道交易流水号"
)
private
String
tradeNo
;
@Schema
(
description
=
"交易时间,支付成功返回"
)
private
String
tradeTime
;
@Schema
(
description
=
"订单标题"
)
private
String
orderTitle
;
@Schema
(
description
=
"订单手续费"
)
private
String
fee
;
@Schema
(
description
=
"结算金额"
)
private
String
actAmt
;
@Schema
(
description
=
"买家用户号"
)
private
String
buyerId
;
@Schema
(
description
=
"对应微信、支付宝小票上交易单号"
)
private
String
tradeTopNo
;
@Schema
(
description
=
"交易账户类型 C-贷记卡,D-借记卡,U-未知"
)
private
String
cardType
;
@Schema
(
description
=
"报文签名值"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotBlank
(
message
=
"签名不能为空"
)
private
String
sign
;
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/admin/resourceorder/vo/WpgjPayNotifyRespDTO.java
deleted
100644 → 0
View file @
fa76472d
package
com
.
luhu
.
computility
.
module
.
compute
.
controller
.
admin
.
resourceorder
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
/**
* WPGJ旺铺聚合支付回调响应DTO
*
* @author jonyl
*/
@Schema
(
description
=
"WPGJ旺铺聚合支付回调响应DTO"
)
@Data
public
class
WpgjPayNotifyRespDTO
{
@Schema
(
description
=
"应答码"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"00"
)
private
String
code
;
@Schema
(
description
=
"对应code码内容描述"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"成功"
)
private
String
msg
;
@Schema
(
description
=
"对应时间戳"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"20251027123456789"
)
private
String
timestamp
;
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/app/resourceorder/AppResourceOrderController.java
View file @
842a425c
...
@@ -7,7 +7,7 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
...
@@ -7,7 +7,7 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO
;
import
com.luhu.computility.module.
pay.controller.app.order.vo.App
PayOrderSubmitRespVO
;
import
com.luhu.computility.module.
compute.controller.app.resourceorder.vo.AppWpgj
PayOrderSubmitRespVO
;
import
com.luhu.computility.module.compute.service.resourceorder.ResourceOrderService
;
import
com.luhu.computility.module.compute.service.resourceorder.ResourceOrderService
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Parameter
;
import
io.swagger.v3.oas.annotations.Parameter
;
...
@@ -42,9 +42,9 @@ public class AppResourceOrderController {
...
@@ -42,9 +42,9 @@ public class AppResourceOrderController {
@PostMapping
(
"/create-wpgj"
)
@PostMapping
(
"/create-wpgj"
)
@Operation
(
summary
=
"创建算力资源订单(旺铺聚合支付)"
)
@Operation
(
summary
=
"创建算力资源订单(旺铺聚合支付)"
)
public
CommonResult
<
AppPayOrderSubmitRespVO
>
createResourceOrderWithWpgj
(
@Valid
@RequestBody
AppResourceOrderCreateReqVO
createReqVO
)
{
public
CommonResult
<
App
Wpgj
PayOrderSubmitRespVO
>
createResourceOrderWithWpgj
(
@Valid
@RequestBody
AppResourceOrderCreateReqVO
createReqVO
)
{
Long
userId
=
getLoginUserId
();
Long
userId
=
getLoginUserId
();
AppPayOrderSubmitRespVO
respVO
=
resourceOrderService
.
createUserResourceOrderWithWpgj
(
userId
,
createReqVO
);
App
Wpgj
PayOrderSubmitRespVO
respVO
=
resourceOrderService
.
createUserResourceOrderWithWpgj
(
userId
,
createReqVO
);
return
success
(
respVO
);
return
success
(
respVO
);
}
}
...
...
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/controller/app/resourceorder/vo/AppWpgjPayOrderSubmitRespVO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
compute
.
controller
.
app
.
resourceorder
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
javax.validation.constraints.NotNull
;
/**
* 用户 APP - WPGJ旺铺聚合支付订单提交 Response VO
* 独立于老支付系统的WPGJ支付响应
*
* @author jony
*/
@Schema
(
description
=
"用户 APP - WPGJ旺铺聚合支付订单提交 Response VO"
)
@Data
public
class
AppWpgjPayOrderSubmitRespVO
{
@Schema
(
description
=
"订单ID(用于前端轮询支付状态)"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"123456"
)
@NotNull
(
message
=
"订单ID不能为空"
)
private
Long
id
;
@Schema
(
description
=
"支付状态"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"10"
)
@NotNull
(
message
=
"支付状态不能为空"
)
private
Integer
status
;
@Schema
(
description
=
"展示模式"
,
example
=
"url"
)
private
String
displayMode
;
@Schema
(
description
=
"展示内容(支付链接等)"
,
example
=
"https://example.com/pay"
)
private
String
displayContent
;
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/dal/mysql/resourceorder/ResourceOrderMapper.java
View file @
842a425c
...
@@ -72,4 +72,10 @@ public interface ResourceOrderMapper extends BaseMapperX<ResourceOrderDO> {
...
@@ -72,4 +72,10 @@ public interface ResourceOrderMapper extends BaseMapperX<ResourceOrderDO> {
.
orderByDesc
(
ResourceOrderDO:
:
getId
));
.
orderByDesc
(
ResourceOrderDO:
:
getId
));
}
}
default
ResourceOrderDO
selectByOrderNo
(
String
orderNo
)
{
return
selectOne
(
new
LambdaQueryWrapperX
<
ResourceOrderDO
>()
.
eq
(
ResourceOrderDO:
:
getOrderNo
,
orderNo
)
.
eq
(
ResourceOrderDO:
:
getDeleted
,
false
));
}
}
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/service/resourceorder/ResourceOrderService.java
View file @
842a425c
...
@@ -8,7 +8,8 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
...
@@ -8,7 +8,8 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppWpgjPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.pojo.PageParam
;
import
com.luhu.computility.framework.common.pojo.PageParam
;
...
@@ -79,9 +80,9 @@ public interface ResourceOrderService {
...
@@ -79,9 +80,9 @@ public interface ResourceOrderService {
*
*
* @param userId 用户ID
* @param userId 用户ID
* @param createReqVO 创建信息
* @param createReqVO 创建信息
* @return 支付提交响应
* @return
WPGJ
支付提交响应
*/
*/
AppPayOrderSubmitRespVO
createUserResourceOrderWithWpgj
(
Long
userId
,
@Valid
AppResourceOrderCreateReqVO
createReqVO
);
App
Wpgj
PayOrderSubmitRespVO
createUserResourceOrderWithWpgj
(
Long
userId
,
@Valid
AppResourceOrderCreateReqVO
createReqVO
);
/**
/**
* 更新订单为已支付(支付回调使用)
* 更新订单为已支付(支付回调使用)
...
@@ -132,4 +133,28 @@ public interface ResourceOrderService {
...
@@ -132,4 +133,28 @@ public interface ResourceOrderService {
*/
*/
boolean
updateRequestInvoice
(
AppResourceOrderInvoiceReqVO
reqVO
);
boolean
updateRequestInvoice
(
AppResourceOrderInvoiceReqVO
reqVO
);
/**
* 根据订单号获取算力资源订单
*
* @param orderNo 订单号
* @return 算力资源订单
*/
ResourceOrderDO
getResourceOrderByOrderNo
(
String
orderNo
);
/**
* WPGJ支付成功回调更新订单状态
*
* @param orderId 订单ID
* @param notifyDTO WPGJ回调通知
*/
void
updateOrderPaidByWpgj
(
Long
orderId
,
WpgjPayNotifyDTO
notifyDTO
);
/**
* WPGJ支付失败回调更新订单状态
*
* @param orderId 订单ID
* @param notifyDTO WPGJ回调通知
*/
void
updateOrderFailedByWpgj
(
Long
orderId
,
WpgjPayNotifyDTO
notifyDTO
);
}
}
\ No newline at end of file
computility-module-compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute/service/resourceorder/ResourceOrderServiceImpl.java
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
compute
.
service
.
resourceorder
;
package
com
.
luhu
.
computility
.
module
.
compute
.
service
.
resourceorder
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
com.luhu.computility.framework.common.exception.ServiceException
;
import
com.luhu.computility.framework.common.exception.ServiceException
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.framework.common.util.object.BeanUtils
;
import
com.luhu.computility.framework.common.util.string.StrUtils
;
import
com.luhu.computility.framework.common.util.string.StrUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
com.luhu.computility.module.compute.config.ResourceOrderProperties
;
import
org.springframework.stereotype.Service
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderPageReqVO
;
import
javax.annotation.Resource
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderRespVO
;
import
org.springframework.validation.annotation.Validated
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderSaveReqVO
;
import
org.springframework.transaction.annotation.Transactional
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.*
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
com.luhu.computility.module.compute.controller.admin.resourceorder.vo.*
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO
;
import
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO
;
import
com.luhu.computility.framework.common.pojo.PageResult
;
import
com.luhu.computility.framework.common.pojo.PageParam
;
import
com.luhu.computility.framework.common.util.object.BeanUtils
;
import
com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper
;
import
com.luhu.computility.module.compute.dal.dataobject.resourcesku.ResourceSkuDO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourcesku.ResourceSkuDO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourcespu.ResourceSpuDO
;
import
com.luhu.computility.module.compute.dal.dataobject.resourcespu.ResourceSpuDO
;
import
com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper
;
import
com.luhu.computility.module.compute.dal.redis.no.ResourceOrderNoRedisDAO
;
import
com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus
;
import
com.luhu.computility.module.compute.enums.ResourceOrderStatus
;
import
com.luhu.computility.module.compute.service.resourcecategory.ResourceCategoryService
;
import
com.luhu.computility.module.compute.service.resourcesku.ResourceSkuService
;
import
com.luhu.computility.module.compute.service.resourcesku.ResourceSkuService
;
import
com.luhu.computility.module.compute.service.resourcespu.ResourceSpuService
;
import
com.luhu.computility.module.compute.service.resourcespu.ResourceSpuService
;
import
com.luhu.computility.module.compute.service.resourcecategory.ResourceCategoryService
;
import
com.luhu.computility.module.compute.enums.ResourceOrderStatus
;
import
com.luhu.computility.module.compute.enums.ResourceOrderRefundStatus
;
import
com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus
;
import
com.luhu.computility.module.compute.config.ResourceOrderProperties
;
import
com.luhu.computility.module.pay.api.order.PayOrderApi
;
import
com.luhu.computility.module.pay.api.order.PayOrderApi
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.wpgj.PayOrderWpgjApi
;
import
com.luhu.computility.module.pay.api.wpgj.dto.PayOrderWpgjCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.api.wpgj.vo.WpgjPayOrderSubmitReqVO
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
servlet
.
ServletUtils
.
getClientIP
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
date
.
LocalDateTimeUtils
.
addTime
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.validation.annotation.Validated
;
import
javax.annotation.Resource
;
import
java.time.LocalDateTime
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Objects
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
exception
.
util
.
ServiceExceptionUtil
.
exception
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
exception
.
util
.
ServiceExceptionUtil
.
exception
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
collection
.
CollectionUtils
.
convertList
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
collection
.
CollectionUtils
.
convertList
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
collection
.
CollectionUtils
.
diffList
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
date
.
LocalDateTimeUtils
.
addTime
;
import
static
com
.
luhu
.
computility
.
framework
.
common
.
util
.
servlet
.
ServletUtils
.
getClientIP
;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ErrorCodeConstants
.*;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ErrorCodeConstants
.*;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ResourceOrderRefundStatus
.
NOT_REFUND
;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ResourceOrderInvoiceStatus
.
UNINVOICE
;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ResourceOrderInvoiceStatus
.
UNINVOICE
;
import
com.luhu.computility.module.compute.dal.redis.no.ResourceOrderNoRedisDAO
;
import
static
com
.
luhu
.
computility
.
module
.
compute
.
enums
.
ResourceOrderRefundStatus
.
NOT_REFUND
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
/**
/**
* 算力资源订单 Service 实现类
* 算力资源订单 Service 实现类
...
@@ -80,6 +78,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
...
@@ -80,6 +78,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
private
PayOrderApi
payOrderApi
;
private
PayOrderApi
payOrderApi
;
@Resource
@Resource
private
PayOrderWpgjApi
payOrderWpgjApi
;
@Resource
private
PayOrderService
payOrderService
;
private
PayOrderService
payOrderService
;
@Resource
@Resource
...
@@ -88,6 +89,10 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
...
@@ -88,6 +89,10 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Resource
@Resource
private
ResourceOrderNoRedisDAO
resourceOrderNoRedisDAO
;
private
ResourceOrderNoRedisDAO
resourceOrderNoRedisDAO
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@Override
@Override
public
Long
createResourceOrder
(
ResourceOrderSaveReqVO
createReqVO
)
{
public
Long
createResourceOrder
(
ResourceOrderSaveReqVO
createReqVO
)
{
// 插入
// 插入
...
@@ -285,6 +290,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
...
@@ -285,6 +290,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
return
resourceOrderNoRedisDAO
.
generate
(
ResourceOrderNoRedisDAO
.
RESOURCE_ORDER_NO_PREFIX
);
return
resourceOrderNoRedisDAO
.
generate
(
ResourceOrderNoRedisDAO
.
RESOURCE_ORDER_NO_PREFIX
);
}
}
/**
/**
* 校验支付订单的合法性
* 校验支付订单的合法性
*
*
...
@@ -443,7 +449,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
...
@@ -443,7 +449,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Override
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
AppPayOrderSubmitRespVO
createUserResourceOrderWithWpgj
(
Long
userId
,
AppResourceOrderCreateReqVO
createReqVO
)
{
public
App
Wpgj
PayOrderSubmitRespVO
createUserResourceOrderWithWpgj
(
Long
userId
,
AppResourceOrderCreateReqVO
createReqVO
)
{
// 1. 构建订单
// 1. 构建订单
ResourceOrderDO
order
=
buildResourceOrder
(
userId
,
createReqVO
);
ResourceOrderDO
order
=
buildResourceOrder
(
userId
,
createReqVO
);
...
@@ -451,61 +457,158 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
...
@@ -451,61 +457,158 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
resourceOrderMapper
.
insert
(
order
);
resourceOrderMapper
.
insert
(
order
);
// 3. 创建旺铺聚合支付订单
// 3. 创建旺铺聚合支付订单
AppPayOrderSubmitRespVO
payRespVO
=
null
;
App
Wpgj
PayOrderSubmitRespVO
payRespVO
=
null
;
if
(
order
.
getPaymentPrice
()
>
0
)
{
if
(
order
.
getPaymentPrice
()
>
0
)
{
payRespVO
=
create
PayOrderWithWpgj
(
order
);
payRespVO
=
create
WpgjPayOrder
(
order
);
}
else
{
}
else
{
// 如果价格为0,返回成功状态
// 如果价格为0,返回成功状态,使用资源订单ID
payRespVO
=
new
AppPayOrderSubmitRespVO
();
payRespVO
=
new
AppWpgjPayOrderSubmitRespVO
();
payRespVO
.
setId
(
order
.
getId
());
// 价格为0时没有WPGJ订单ID,使用资源订单ID
payRespVO
.
setStatus
(
PayOrderStatusEnum
.
SUCCESS
.
getStatus
());
payRespVO
.
setStatus
(
PayOrderStatusEnum
.
SUCCESS
.
getStatus
());
}
}
// 4. 保存支付订单ID到响应中(用于前端轮询)
if
(
payRespVO
!=
null
&&
order
.
getPayOrderId
()
!=
null
)
{
// 通过扩展字段传递payOrderId
payRespVO
.
setOrderExtensionId
(
order
.
getPayOrderId
());
}
return
payRespVO
;
return
payRespVO
;
}
}
/**
/**
* 创建
旺铺聚合支付订单
* 创建
WPGJ旺铺聚合支付订单(完全独立实现)
*/
*/
private
App
PayOrderSubmitRespVO
createPayOrderWithWpgj
(
ResourceOrderDO
order
)
{
private
App
WpgjPayOrderSubmitRespVO
createWpgjPayOrder
(
ResourceOrderDO
order
)
{
try
{
try
{
// 1. 创建支付订单(用于数据库记录)
log
.
info
(
"[createWpgjPayOrder] 开始创建WPGJ支付订单,资源订单ID: {}, 支付金额: {}"
,
PayOrderCreateReqDTO
payOrderCreateReqDTO
=
new
PayOrderCreateReqDTO
()
order
.
getId
(),
order
.
getPaymentPrice
());
.
setAppKey
(
resourceOrderProperties
.
getPayAppKey
()).
setUserIp
(
order
.
getUserIp
());
payOrderCreateReqDTO
.
setMerchantOrderId
(
String
.
valueOf
(
order
.
getId
()));
// 1. 创建WPGJ支付订单记录
PayOrderWpgjCreateReqDTO
wpgjCreateReqDTO
=
new
PayOrderWpgjCreateReqDTO
();
wpgjCreateReqDTO
.
setBusinessType
(
1
);
// 1-算力资源订单
wpgjCreateReqDTO
.
setMerOrderId
(
String
.
valueOf
(
order
.
getId
()));
String
subject
=
order
.
getSpuName
()
+
" - "
+
getDurationDaysFromSku
(
order
.
getSkuId
())
+
"天"
;
String
subject
=
order
.
getSpuName
()
+
" - "
+
getDurationDaysFromSku
(
order
.
getSkuId
())
+
"天"
;
subject
=
StrUtils
.
maxLength
(
subject
,
PayOrderCreateReqDTO
.
SUBJECT_MAX_LENGTH
);
subject
=
StrUtils
.
maxLength
(
subject
,
64
);
// WPGJ订单标题最大64位
payOrderCreateReqDTO
.
setSubject
(
subject
);
wpgjCreateReqDTO
.
setOrderTitle
(
subject
);
payOrderCreateReqDTO
.
setBody
(
subject
);
wpgjCreateReqDTO
.
setOrderAmt
(
String
.
valueOf
(
order
.
getPaymentPrice
()
/
100.0
));
// 转换为元
payOrderCreateReqDTO
.
setPrice
(
order
.
getPaymentPrice
().
intValue
())
.
setExpireTime
(
addTime
(
resourceOrderProperties
.
getPayExpireTime
()));
Long
wpgjOrderId
=
payOrderWpgjApi
.
createOrderWpgj
(
wpgjCreateReqDTO
);
log
.
info
(
"[createWpgjPayOrder] WPGJ订单创建成功,资源订单ID: {}, WPGJ订单ID: {}"
,
order
.
getId
(),
wpgjOrderId
);
Long
payOrderId
=
payOrderApi
.
createOrderWpgj
(
payOrderCreateReqDTO
);
// 2. 更新算力资源订单的WPGJ订单ID
resourceOrderMapper
.
updateById
(
new
ResourceOrderDO
().
setId
(
order
.
getId
()).
setPayOrderId
(
wpgjOrderId
));
// 2. 提交支付订单(使用旺铺聚合支付)
// 3. 调用WPGJ支付提交API获取支付链接
AppPayOrderSubmitReqVO
submitReqDTO
=
new
AppPayOrderSubmitReqVO
();
WpgjPayOrderSubmitReqVO
submitReqVO
=
new
WpgjPayOrderSubmitReqVO
();
submitReqDTO
.
setId
(
payOrderId
);
submitReqVO
.
setId
(
wpgjOrderId
);
submitReqDTO
.
setChannelCode
(
"wpgj_dynamic"
);
AppPayOrderSubmitRespVO
submitRespVO
=
payOrderService
.
submitWpgjOrder
(
submitReqDTO
,
order
.
getUserIp
());
AppPayOrderSubmitRespVO
submitRespVO
=
payOrderApi
.
submitWpgjOrder
(
submitReqVO
);
log
.
info
(
"[createWpgjPayOrder] WPGJ支付提交成功,资源订单ID: {}, WPGJ订单ID: {}, 支付状态: {}"
,
order
.
getId
(),
wpgjOrderId
,
submitRespVO
.
getStatus
());
// 3. 更新到算力资源订单上
// 4. 构建返回数据 - 包含支付链接
resourceOrderMapper
.
updateById
(
new
ResourceOrderDO
().
setId
(
order
.
getId
()).
setPayOrderId
(
payOrderId
));
AppWpgjPayOrderSubmitRespVO
respVO
=
new
AppWpgjPayOrderSubmitRespVO
();
order
.
setPayOrderId
(
payOrderId
);
respVO
.
setId
(
wpgjOrderId
);
// 返回WPGJ订单ID,用于前端轮询
respVO
.
setStatus
(
submitRespVO
.
getStatus
());
respVO
.
setDisplayMode
(
submitRespVO
.
getDisplayMode
());
respVO
.
setDisplayContent
(
submitRespVO
.
getDisplayContent
());
// 支付链接
log
.
info
(
"[createPayOrderWithWpgj] 旺铺聚合支付订单创建成功,订单ID: {}, 支付订单ID: {}"
,
order
.
getId
(),
payOrderId
);
log
.
info
(
"[createWpgjPayOrder] WPGJ支付订单创建完成,资源订单ID: {}, WPGJ订单ID: {}, 支付链接: {}"
,
order
.
getId
(),
wpgjOrderId
,
submitRespVO
.
getDisplayContent
());
return
submitR
espVO
;
return
r
espVO
;
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
log
.
error
(
"[create
PayOrderWithWpgj] 创建旺铺聚合
支付订单失败"
,
e
);
log
.
error
(
"[create
WpgjPayOrder] 创建WPGJ
支付订单失败"
,
e
);
throw
new
ServiceException
(
"创建支付订单失败: "
+
e
.
getMessage
());
throw
new
ServiceException
(
"创建支付订单失败: "
+
e
.
getMessage
());
}
}
}
}
@Override
public
ResourceOrderDO
getResourceOrderByOrderNo
(
String
orderNo
)
{
return
resourceOrderMapper
.
selectByOrderNo
(
orderNo
);
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
updateOrderPaidByWpgj
(
Long
orderId
,
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
log
.
info
(
"[updateOrderPaidByWpgj] 开始处理WPGJ支付成功回调,订单ID: {}, WPGJ订单号: {}"
,
orderId
,
notifyDTO
.
getOrderId
());
// 1. 校验算力资源订单是否存在
ResourceOrderDO
order
=
validateResourceOrderExists
(
orderId
);
// 2. 校验订单状态,避免重复处理
if
(
ResourceOrderStatus
.
PAID
.
getValue
()
==
order
.
getStatus
())
{
log
.
warn
(
"[updateOrderPaidByWpgj] 订单已经是支付状态,订单ID: {}"
,
orderId
);
return
;
}
if
(!
ResourceOrderStatus
.
UNPAID
.
getValue
().
equals
(
order
.
getStatus
()))
{
log
.
error
(
"[updateOrderPaidByWpgj] 订单状态不是待支付,无法更新为已支付,订单ID: {}, 当前状态: {}"
,
orderId
,
order
.
getStatus
());
return
;
}
// 3. 校验支付金额是否匹配
String
wpgjOrderAmt
=
notifyDTO
.
getOrderAmt
();
// WPGJ回调金额单位是元
long
resourceOrderAmt
=
order
.
getPaymentPrice
()
/
100
;
// 转换为元
if
(!
wpgjOrderAmt
.
equals
(
String
.
valueOf
(
resourceOrderAmt
)))
{
log
.
error
(
"[updateOrderPaidByWpgj] 支付金额不匹配,订单ID: {}, WPGJ金额: {}, 订单金额: {}"
,
orderId
,
wpgjOrderAmt
,
resourceOrderAmt
);
return
;
}
// 4. 更新算力资源订单状态为已支付
ResourceOrderDO
updateOrder
=
new
ResourceOrderDO
();
updateOrder
.
setId
(
orderId
);
updateOrder
.
setStatus
(
ResourceOrderStatus
.
PAID
.
getValue
());
updateOrder
.
setPayTime
(
LocalDateTime
.
now
());
resourceOrderMapper
.
updateById
(
updateOrder
);
log
.
info
(
"[updateOrderPaidByWpgj] WPGJ支付成功回调处理完成,订单ID: {}, WPGJ订单号: {}"
,
orderId
,
notifyDTO
.
getOrderId
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[updateOrderPaidByWpgj] 处理WPGJ支付成功回调异常,订单ID: {}"
,
orderId
,
e
);
throw
e
;
}
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
updateOrderFailedByWpgj
(
Long
orderId
,
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
log
.
info
(
"[updateOrderFailedByWpgj] 开始处理WPGJ支付失败回调,订单ID: {}, WPGJ订单号: {}"
,
orderId
,
notifyDTO
.
getOrderId
());
// 1. 校验算力资源订单是否存在
ResourceOrderDO
order
=
validateResourceOrderExists
(
orderId
);
// 2. 校验订单状态,避免重复处理
if
(
ResourceOrderStatus
.
CANCELED
.
getValue
()
==
order
.
getStatus
())
{
log
.
warn
(
"[updateOrderFailedByWpgj] 订单已经是取消状态,订单ID: {}"
,
orderId
);
return
;
}
if
(!
ResourceOrderStatus
.
UNPAID
.
getValue
().
equals
(
order
.
getStatus
()))
{
log
.
error
(
"[updateOrderFailedByWpgj] 订单状态不是待支付,无法更新为已取消,订单ID: {}, 当前状态: {}"
,
orderId
,
order
.
getStatus
());
return
;
}
// 3. 更新算力资源订单状态为已取消(支付失败)
ResourceOrderDO
updateOrder
=
new
ResourceOrderDO
();
updateOrder
.
setId
(
orderId
);
updateOrder
.
setStatus
(
ResourceOrderStatus
.
CANCELED
.
getValue
());
updateOrder
.
setCancelTime
(
LocalDateTime
.
now
());
resourceOrderMapper
.
updateById
(
updateOrder
);
log
.
info
(
"[updateOrderFailedByWpgj] WPGJ支付失败回调处理完成,订单ID: {}, WPGJ订单号: {}"
,
orderId
,
notifyDTO
.
getOrderId
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[updateOrderFailedByWpgj] 处理WPGJ支付失败回调异常,订单ID: {}"
,
orderId
,
e
);
throw
e
;
}
}
}
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApi.java
View file @
842a425c
...
@@ -2,6 +2,8 @@ package com.luhu.computility.module.pay.api.order;
...
@@ -2,6 +2,8 @@ package com.luhu.computility.module.pay.api.order;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.api.wpgj.vo.WpgjPayOrderSubmitReqVO
;
import
javax.validation.Valid
;
import
javax.validation.Valid
;
...
@@ -45,4 +47,12 @@ public interface PayOrderApi {
...
@@ -45,4 +47,12 @@ public interface PayOrderApi {
*/
*/
void
updatePayOrderPrice
(
Long
id
,
Integer
payPrice
);
void
updatePayOrderPrice
(
Long
id
,
Integer
payPrice
);
/**
* 提交WPGJ旺铺聚合支付订单
*
* @param reqVO 提交请求
* @return 支付提交响应
*/
AppPayOrderSubmitRespVO
submitWpgjOrder
(
@Valid
WpgjPayOrderSubmitReqVO
reqVO
);
}
}
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/PayOrderApiImpl.java
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
order
;
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
order
;
import
cn.hutool.http.HttpRequest
;
import
cn.hutool.http.HttpResponse
;
import
cn.hutool.json.JSONObject
;
import
com.luhu.computility.framework.common.exception.util.ServiceExceptionUtil
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.api.order.dto.WpgjPayOrderRespDTO
;
import
com.luhu.computility.module.pay.convert.order.PayOrderConvert
;
import
com.luhu.computility.module.pay.convert.order.PayOrderConvert
;
import
com.luhu.computility.module.pay.dal.dataobject.order.PayOrderDO
;
import
com.luhu.computility.module.pay.dal.dataobject.order.PayOrderDO
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
import
com.luhu.computility.module.pay.dal.mysql.wpgj.PayOrderWpgjMapper
;
import
com.luhu.computility.module.pay.enums.ErrorCodeConstants
;
import
com.luhu.computility.module.pay.enums.WpgjOrderStatusEnum
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjCryptoUtils
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.api.wpgj.vo.WpgjPayOrderSubmitReqVO
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.validation.Valid
;
import
java.net.URLEncoder
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
/**
/**
* 支付单 API 实现类
* 支付单 API 实现类
...
@@ -15,11 +34,18 @@ import javax.annotation.Resource;
...
@@ -15,11 +34,18 @@ import javax.annotation.Resource;
* @author 芋道源码
* @author 芋道源码
*/
*/
@Service
@Service
@Slf4j
public
class
PayOrderApiImpl
implements
PayOrderApi
{
public
class
PayOrderApiImpl
implements
PayOrderApi
{
@Resource
@Resource
private
PayOrderService
payOrderService
;
private
PayOrderService
payOrderService
;
@Resource
private
PayOrderWpgjMapper
payOrderWpgjMapper
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@Override
@Override
public
Long
createOrder
(
PayOrderCreateReqDTO
reqDTO
)
{
public
Long
createOrder
(
PayOrderCreateReqDTO
reqDTO
)
{
return
payOrderService
.
createOrder
(
reqDTO
);
return
payOrderService
.
createOrder
(
reqDTO
);
...
@@ -41,4 +67,161 @@ public class PayOrderApiImpl implements PayOrderApi {
...
@@ -41,4 +67,161 @@ public class PayOrderApiImpl implements PayOrderApi {
payOrderService
.
updatePayOrderPrice
(
id
,
payPrice
);
payOrderService
.
updatePayOrderPrice
(
id
,
payPrice
);
}
}
@Override
public
AppPayOrderSubmitRespVO
submitWpgjOrder
(
@Valid
WpgjPayOrderSubmitReqVO
reqVO
)
{
try
{
log
.
info
(
"[submitWpgjOrder] 开始提交WPGJ支付,订单ID: {}"
,
reqVO
.
getId
());
// 1. 查找WPGJ订单
PayOrderWpgjDO
wpgjOrder
=
validateWpgjOrderCanSubmit
(
reqVO
.
getId
());
// 2. 调用WPGJ API获取支付链接
WpgjPayOrderRespDTO
wpgjResp
=
callWpgjApi
(
wpgjOrder
);
// 3. 更新WPGJ订单状态
updateWpgjOrderAfterSubmit
(
wpgjOrder
,
wpgjResp
);
// 4. 构建返回结果
AppPayOrderSubmitRespVO
respVO
=
new
AppPayOrderSubmitRespVO
();
respVO
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
());
respVO
.
setWpgjOrderId
(
wpgjOrder
.
getId
());
// 设置WPGJ订单ID供前端轮询使用
if
(
wpgjResp
!=
null
&&
wpgjResp
.
getDisplayContent
()
!=
null
)
{
respVO
.
setDisplayMode
(
wpgjResp
.
getDisplayMode
());
respVO
.
setDisplayContent
(
wpgjResp
.
getDisplayContent
());
}
return
respVO
;
}
catch
(
Exception
e
)
{
log
.
error
(
"[submitWpgjOrder] 提交WPGJ支付失败"
,
e
);
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_SUBMIT_CHANNEL_ERROR
,
"WPGJ_ERROR"
,
"WPGJ支付提交失败: "
+
e
.
getMessage
());
}
}
/**
* 校验WPGJ订单是否可以提交
*/
private
PayOrderWpgjDO
validateWpgjOrderCanSubmit
(
Long
id
)
{
PayOrderWpgjDO
wpgjOrder
=
payOrderWpgjMapper
.
selectById
(
id
);
if
(
wpgjOrder
==
null
)
{
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_NOT_FOUND
);
}
if
(
WpgjOrderStatusEnum
.
isSuccess
(
wpgjOrder
.
getOrderStatus
()))
{
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_STATUS_IS_SUCCESS
);
}
if
(!
WpgjOrderStatusEnum
.
PROCESSING
.
getStatus
().
equals
(
wpgjOrder
.
getOrderStatus
()))
{
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_STATUS_IS_NOT_WAITING
);
}
return
wpgjOrder
;
}
/**
* 调用WPGJ支付API
*/
private
WpgjPayOrderRespDTO
callWpgjApi
(
PayOrderWpgjDO
wpgjOrder
)
{
try
{
log
.
info
(
"[callWpgjApi] 开始调用WPGJ支付API,订单号: {}"
,
wpgjOrder
.
getMerOrderId
());
// 1. 构建业务数据
JSONObject
businessData
=
new
JSONObject
();
businessData
.
set
(
"mer_no"
,
wpgjPayProperties
.
getMerNo
());
businessData
.
set
(
"mer_code"
,
wpgjPayProperties
.
getMerCode
());
businessData
.
set
(
"term_code"
,
wpgjPayProperties
.
getTermCode
());
businessData
.
set
(
"mer_order_id"
,
wpgjOrder
.
getMerOrderId
());
businessData
.
set
(
"order_amt"
,
String
.
valueOf
(
wpgjOrder
.
getOrderAmt
()));
businessData
.
set
(
"organiz_no"
,
wpgjPayProperties
.
getOrganizNo
());
businessData
.
set
(
"cashier_type"
,
"1"
);
businessData
.
set
(
"return_url"
,
""
);
// WPGJ订单暂不使用return_url
businessData
.
set
(
"notifyurl"
,
wpgjPayProperties
.
getNotifyUrl
());
// 2. 构建加密请求数据
String
encryptedRequest
=
WpgjCryptoUtils
.
buildEncryptedRequest
(
businessData
,
wpgjPayProperties
.
getOrganizNo
(),
wpgjPayProperties
.
getPublicKey
()
);
// 3. URL编码
String
encodedRequest
=
URLEncoder
.
encode
(
encryptedRequest
,
"UTF-8"
);
log
.
info
(
"[callWpgjApi] 发送加密请求数据: {}"
,
encryptedRequest
);
// 4. 发送HTTP请求
HttpResponse
response
=
HttpRequest
.
post
(
wpgjPayProperties
.
getApiUrl
())
.
header
(
"Content-Type"
,
"application/x-www-form-urlencoded"
)
.
body
(
encodedRequest
)
.
timeout
(
30000
)
.
execute
();
// 5. 处理响应
if
(!
response
.
isOk
())
{
log
.
error
(
"[callWpgjApi] WPGJ API调用失败,HTTP状态码: {}"
,
response
.
getStatus
());
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_SUBMIT_CHANNEL_ERROR
,
"HTTP_ERROR"
,
"支付网关调用失败,状态码: "
+
response
.
getStatus
());
}
String
responseData
=
response
.
body
();
// 6. 解析响应结果
JSONObject
responseJson
=
new
JSONObject
(
responseData
);
if
(
"0000"
.
equals
(
responseJson
.
getStr
(
"code"
)))
{
JSONObject
decryptedResponse
=
WpgjCryptoUtils
.
decryptResponse
(
responseData
,
wpgjPayProperties
.
getPrivateKey
());
log
.
info
(
"[callWpgjApi] WPGJ API解密后的完整响应: {}"
,
decryptedResponse
);
return
parseWpgjApiResponse
(
decryptedResponse
,
wpgjOrder
.
getMerOrderId
());
}
else
{
return
parseWpgjError
(
responseJson
,
wpgjOrder
.
getMerOrderId
());
}
}
catch
(
Exception
e
)
{
log
.
error
(
"[callWpgjApi] WPGJ API调用异常,订单号: {}"
,
wpgjOrder
.
getMerOrderId
(),
e
);
throw
ServiceExceptionUtil
.
exception
(
ErrorCodeConstants
.
PAY_ORDER_SUBMIT_CHANNEL_ERROR
,
"API_ERROR"
,
"支付网关调用异常: "
+
e
.
getMessage
());
}
}
/**
* 解析WPGJ API成功响应
*/
private
WpgjPayOrderRespDTO
parseWpgjApiResponse
(
JSONObject
response
,
String
outTradeNo
)
{
WpgjPayOrderRespDTO
respDTO
=
new
WpgjPayOrderRespDTO
();
respDTO
.
setMerchantOrderId
(
outTradeNo
);
respDTO
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
());
// 解析data字段中的payUrl
JSONObject
data
=
response
.
getJSONObject
(
"data"
);
if
(
data
!=
null
&&
data
.
containsKey
(
"payUrl"
))
{
String
payUrl
=
data
.
getStr
(
"payUrl"
);
respDTO
.
setDisplayMode
(
"pay_url"
);
respDTO
.
setDisplayContent
(
payUrl
);
log
.
info
(
"[parseWpgjApiResponse] 获取到支付URL: {}"
,
payUrl
);
}
return
respDTO
;
}
/**
* 解析WPGJ API错误响应
*/
private
WpgjPayOrderRespDTO
parseWpgjError
(
JSONObject
response
,
String
outTradeNo
)
{
WpgjPayOrderRespDTO
respDTO
=
new
WpgjPayOrderRespDTO
();
respDTO
.
setMerchantOrderId
(
outTradeNo
);
respDTO
.
setStatus
(
PayOrderStatusEnum
.
CLOSED
.
getStatus
());
respDTO
.
setChannelErrorCode
(
response
.
getStr
(
"code"
));
respDTO
.
setChannelErrorMsg
(
response
.
getStr
(
"msg"
));
log
.
error
(
"[parseWpgjError] WPGJ API返回错误: code={}, msg={}"
,
response
.
getStr
(
"code"
),
response
.
getStr
(
"msg"
));
return
respDTO
;
}
/**
* 更新WPGJ订单提交后的状态
*/
private
void
updateWpgjOrderAfterSubmit
(
PayOrderWpgjDO
wpgjOrder
,
WpgjPayOrderRespDTO
wpgjResp
)
{
// 这里可以根据需要更新WPGJ订单的状态,比如记录支付链接等
log
.
info
(
"[updateWpgjOrderAfterSubmit] WPGJ订单提交完成,订单ID: {}"
,
wpgjOrder
.
getId
());
}
}
}
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/order/dto/WpgjPayOrderRespDTO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
order
.
dto
;
import
lombok.Data
;
/**
* WPGJ旺铺聚合支付响应 DTO
*
* @author jonyl
*/
@Data
public
class
WpgjPayOrderRespDTO
{
/**
* 商户订单号
*/
private
String
merchantOrderId
;
/**
* 支付状态
*/
private
Integer
status
;
/**
* 展示模式
*/
private
String
displayMode
;
/**
* 展示内容(支付URL)
*/
private
String
displayContent
;
/**
* 渠道错误码
*/
private
String
channelErrorCode
;
/**
* 渠道错误信息
*/
private
String
channelErrorMsg
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/PayOrderWpgjApi.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
wpgj
;
import
com.luhu.computility.module.pay.api.wpgj.dto.PayOrderWpgjCreateReqDTO
;
import
javax.validation.Valid
;
/**
* WPGJ旺铺聚合支付订单 API 接口
*
* @author jony
*/
public
interface
PayOrderWpgjApi
{
/**
* 创建WPGJ旺铺聚合支付订单
*
* @param reqDTO 创建请求
* @return WPGJ订单ID
*/
Long
createOrderWpgj
(
@Valid
PayOrderWpgjCreateReqDTO
reqDTO
);
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/PayOrderWpgjApiImpl.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
wpgj
;
import
com.luhu.computility.module.pay.api.wpgj.dto.PayOrderWpgjCreateReqDTO
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
import
com.luhu.computility.module.pay.dal.mysql.wpgj.PayOrderWpgjMapper
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.validation.annotation.Validated
;
import
javax.annotation.Resource
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
/**
* WPGJ旺铺聚合支付订单 API 实现类
*
* @author jony
*/
@Service
@Validated
@Slf4j
public
class
PayOrderWpgjApiImpl
implements
PayOrderWpgjApi
{
@Resource
private
PayOrderWpgjMapper
payOrderWpgjMapper
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@Override
public
Long
createOrderWpgj
(
PayOrderWpgjCreateReqDTO
reqDTO
)
{
try
{
log
.
info
(
"[createOrderWpgj] 开始创建WPGJ支付订单,商户订单ID: {}, 订单金额: {}元"
,
reqDTO
.
getMerOrderId
(),
reqDTO
.
getOrderAmt
());
// 1. 构建PayOrderWpgjDO
PayOrderWpgjDO
wpgjOrder
=
new
PayOrderWpgjDO
();
wpgjOrder
.
setBusinessType
(
reqDTO
.
getBusinessType
());
wpgjOrder
.
setMerOrderId
(
reqDTO
.
getMerOrderId
());
wpgjOrder
.
setOrderNo
(
reqDTO
.
getOrderNo
());
wpgjOrder
.
setOrderTitle
(
reqDTO
.
getOrderTitle
());
wpgjOrder
.
setOrderAmt
(
reqDTO
.
getOrderAmt
());
// 单位:元
wpgjOrder
.
setOrderStatus
(
"0"
);
// 0-处理中
wpgjOrder
.
setOrderTime
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmss"
)));
// orderId字段在WPGJ回调时才会设置,创建时保持null
// 从配置获取WPGJ必要字段
if
(
wpgjPayProperties
!=
null
)
{
wpgjOrder
.
setMerNo
(
wpgjPayProperties
.
getMerNo
());
wpgjOrder
.
setMerCode
(
wpgjPayProperties
.
getMerCode
());
}
// deviceNo、paywayCode、sign等字段在WPGJ回调时才会设置,创建时保持null
// 2. 插入pay_order_wpgj表
payOrderWpgjMapper
.
insert
(
wpgjOrder
);
Long
wpgjOrderId
=
wpgjOrder
.
getId
();
log
.
info
(
"[createOrderWpgj] WPGJ订单创建成功,商户订单ID: {}, WPGJ订单ID: {}"
,
reqDTO
.
getMerOrderId
(),
wpgjOrderId
);
// 3. 返回WPGJ订单ID
return
wpgjOrderId
;
}
catch
(
Exception
e
)
{
log
.
error
(
"[createOrderWpgj] 创建WPGJ支付订单失败"
,
e
);
throw
new
RuntimeException
(
"创建支付订单失败: "
+
e
.
getMessage
());
}
}
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/dto/PayOrderWpgjCreateReqDTO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
wpgj
.
dto
;
import
lombok.Data
;
import
org.hibernate.validator.constraints.Length
;
import
javax.validation.constraints.NotEmpty
;
import
javax.validation.constraints.NotNull
;
import
java.io.Serializable
;
/**
* WPGJ旺铺聚合支付单创建 Request DTO
*/
@Data
public
class
PayOrderWpgjCreateReqDTO
implements
Serializable
{
/**
* 业务类型 1-算力资源订单 2-API订单
*/
@NotNull
(
message
=
"业务类型不能为空"
)
private
Integer
businessType
;
/**
* 商户订单ID(对应业务订单ID)
*/
@NotEmpty
(
message
=
"商户订单ID不能为空"
)
private
String
merOrderId
;
/**
* 关联的业务订单号
*/
private
String
orderNo
;
/**
* 订单标题
*/
@NotEmpty
(
message
=
"订单标题不能为空"
)
@Length
(
max
=
64
,
message
=
"订单标题长度不能超过64"
)
private
String
orderTitle
;
/**
* 订单金额,单位:元(注意:WPGJ要求单位是元)
*/
@NotEmpty
(
message
=
"订单金额不能为空"
)
private
String
orderAmt
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/api/wpgj/vo/WpgjPayOrderSubmitReqVO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
api
.
wpgj
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
javax.validation.constraints.NotNull
;
/**
* WPGJ旺铺聚合支付订单提交 Request VO
* 独立于老支付系统的WPGJ专用VO
*
* @author jony
*/
@Schema
(
description
=
"WPGJ旺铺聚合支付订单提交 Request VO"
)
@Data
public
class
WpgjPayOrderSubmitReqVO
{
@Schema
(
description
=
"WPGJ支付订单ID"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"123456"
)
@NotNull
(
message
=
"WPGJ支付订单ID不能为空"
)
private
Long
id
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/admin/notify/WpgjPayController.java
deleted
100644 → 0
View file @
fa76472d
package
com
.
luhu
.
computility
.
module
.
pay
.
controller
.
admin
.
notify
;
import
cn.hutool.core.util.StrUtil
;
import
com.luhu.computility.framework.common.util.json.JsonUtils
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyRespDTO
;
import
com.luhu.computility.module.pay.enums.order.WpgjOrderStatusEnum
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.annotation.security.PermitAll
;
import
javax.annotation.Resource
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.Map
;
/**
* WPGJ旺铺聚合支付回调Controller
*
* @author jonyl
*/
@Tag
(
name
=
"管理后台 - WPGJ旺铺聚合支付回调"
)
@RestController
@RequestMapping
(
"/pay/wpgj"
)
@Slf4j
public
class
WpgjPayController
{
@Resource
private
PayOrderService
payOrderService
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@PostMapping
(
"/notify"
)
@PermitAll
@Operation
(
summary
=
"WPGJ支付异步回调通知"
)
public
WpgjPayNotifyRespDTO
notifyWpgjPay
(
@RequestBody
WpgjPayNotifyDTO
notifyDTO
)
{
WpgjPayNotifyRespDTO
response
=
new
WpgjPayNotifyRespDTO
();
try
{
log
.
info
(
"[notifyWpgjPay] 收到WPGJ支付回调: {}"
,
JsonUtils
.
toJsonString
(
notifyDTO
));
// 1. 验证签名
if
(!
verifyWpgjSignature
(
notifyDTO
))
{
log
.
error
(
"[notifyWpgjPay] WPGJ回调签名验证失败"
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"签名验证失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
// 2. 解析回调数据,构造PayOrderRespDTO
PayOrderRespDTO
notify
=
parseWpgjNotifyData
(
notifyDTO
);
// 3. 处理支付结果通知
// 由于WPGJ是特殊渠道,直接调用内部处理方法
payOrderService
.
notifyOrder
(-
1L
,
notify
);
// 使用-1表示WPGJ特殊渠道
log
.
info
(
"[notifyWpgjPay] WPGJ支付回调处理完成"
);
response
.
setCode
(
"00"
);
response
.
setMsg
(
"成功"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
catch
(
Exception
e
)
{
log
.
error
(
"[notifyWpgjPay] WPGJ支付回调处理失败"
,
e
);
response
.
setCode
(
"99"
);
response
.
setMsg
(
"处理失败"
);
response
.
setTimestamp
(
LocalDateTime
.
now
().
format
(
DateTimeFormatter
.
ofPattern
(
"yyyyMMddHHmmssSSS"
)));
return
response
;
}
}
/**
* 验证WPGJ回调签名
*/
private
boolean
verifyWpgjSignature
(
WpgjPayNotifyDTO
notifyDTO
)
{
try
{
// 1. 构建待签名字符串
StringBuilder
sb
=
new
StringBuilder
();
// 按照字段名ASCII码排序
Map
<
String
,
String
>
sortedParams
=
new
java
.
util
.
TreeMap
<>();
sortedParams
.
put
(
"device_no"
,
notifyDTO
.
getDeviceNo
());
sortedParams
.
put
(
"mer_no"
,
notifyDTO
.
getMerNo
());
sortedParams
.
put
(
"payway_code"
,
notifyDTO
.
getPaywayCode
());
sortedParams
.
put
(
"order_id"
,
notifyDTO
.
getOrderId
());
sortedParams
.
put
(
"mer_order_id"
,
notifyDTO
.
getMerOrderId
());
sortedParams
.
put
(
"order_time"
,
notifyDTO
.
getOrderTime
());
sortedParams
.
put
(
"order_amt"
,
notifyDTO
.
getOrderAmt
());
sortedParams
.
put
(
"order_status"
,
notifyDTO
.
getOrderStatus
());
// 可选字段(非空才加入)
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getMerCode
()))
{
sortedParams
.
put
(
"mer_code"
,
notifyDTO
.
getMerCode
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getGatewayMerOrderId
()))
{
sortedParams
.
put
(
"gateway_mer_order_id"
,
notifyDTO
.
getGatewayMerOrderId
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeNo
()))
{
sortedParams
.
put
(
"trade_no"
,
notifyDTO
.
getTradeNo
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeTime
()))
{
sortedParams
.
put
(
"trade_time"
,
notifyDTO
.
getTradeTime
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getOrderTitle
()))
{
sortedParams
.
put
(
"order_title"
,
notifyDTO
.
getOrderTitle
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getFee
()))
{
sortedParams
.
put
(
"fee"
,
notifyDTO
.
getFee
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getActAmt
()))
{
sortedParams
.
put
(
"act_amt"
,
notifyDTO
.
getActAmt
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getBuyerId
()))
{
sortedParams
.
put
(
"buyer_id"
,
notifyDTO
.
getBuyerId
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getTradeTopNo
()))
{
sortedParams
.
put
(
"trade_top_no"
,
notifyDTO
.
getTradeTopNo
());
}
if
(
StrUtil
.
isNotBlank
(
notifyDTO
.
getCardType
()))
{
sortedParams
.
put
(
"card_type"
,
notifyDTO
.
getCardType
());
}
// 2. 构建签名字符串
for
(
Map
.
Entry
<
String
,
String
>
entry
:
sortedParams
.
entrySet
())
{
if
(
StrUtil
.
isNotBlank
(
entry
.
getValue
()))
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
"&"
);
}
sb
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
entry
.
getValue
());
}
}
// 3. 添加key
String
signKey
=
wpgjPayProperties
.
getSignKey
();
// 签名密钥
sb
.
append
(
"&key="
).
append
(
signKey
);
// 4. 计算MD5签名
String
signStr
=
sb
.
toString
();
String
calculatedSign
=
cn
.
hutool
.
crypto
.
digest
.
DigestUtil
.
md5Hex
(
signStr
).
toUpperCase
();
log
.
info
(
"[verifyWpgjSignature] 待签名字符串: {}"
,
signStr
);
log
.
info
(
"[verifyWpgjSignature] 计算签名: {}"
,
calculatedSign
);
log
.
info
(
"[verifyWpgjSignature] 原始签名: {}"
,
notifyDTO
.
getSign
());
// 5. 验证签名
return
calculatedSign
.
equals
(
notifyDTO
.
getSign
());
}
catch
(
Exception
e
)
{
log
.
error
(
"[verifyWpgjSignature] 签名验证异常"
,
e
);
return
false
;
}
}
/**
* 解析WPGJ回调数据为PayOrderRespDTO
*/
private
PayOrderRespDTO
parseWpgjNotifyData
(
WpgjPayNotifyDTO
notifyDTO
)
{
PayOrderRespDTO
notify
=
new
PayOrderRespDTO
();
// 根据WPGJ回调文档解析字段
notify
.
setOutTradeNo
(
notifyDTO
.
getMerOrderId
());
// 商户订单号
notify
.
setChannelOrderNo
(
notifyDTO
.
getTradeNo
());
// 第三方交易号
notify
.
setStatus
(
parseWpgjStatus
(
notifyDTO
.
getOrderStatus
()));
// 交易状态
// 设置支付成功时间
if
(
WpgjOrderStatusEnum
.
isSuccess
(
notifyDTO
.
getOrderStatus
()))
{
notify
.
setSuccessTime
(
java
.
time
.
LocalDateTime
.
now
());
}
// 设置其他必要的字段
notify
.
setChannelCode
(
"wpgj_dynamic"
);
notify
.
setChannelErrorCode
(
null
);
// 成功时没有错误码
notify
.
setChannelErrorMsg
(
null
);
notify
.
setRawData
(
JsonUtils
.
toJsonString
(
notifyDTO
));
// 保存原始数据
return
notify
;
}
/**
* 解析WPGJ交易状态
*/
private
Integer
parseWpgjStatus
(
String
orderStatus
)
{
if
(
WpgjOrderStatusEnum
.
isSuccess
(
orderStatus
))
{
// 1-成功
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
SUCCESS
.
getStatus
();
}
else
if
(
WpgjOrderStatusEnum
.
isFailedOrClosed
(
orderStatus
))
{
// 0-处理中 2-失败
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
CLOSED
.
getStatus
();
}
else
{
return
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
.
PayOrderStatusEnum
.
WAITING
.
getStatus
();
}
}
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/AppPayOrderController.java
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
controller
.
app
.
order
;
package
com
.
luhu
.
computility
.
module
.
pay
.
controller
.
app
.
order
;
import
cn.hutool.core.util.ObjectUtil
;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.pojo.CommonResult
;
import
com.luhu.computility.framework.common.util.object.BeanUtils
;
import
com.luhu.computility.framework.common.util.object.BeanUtils
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderRespVO
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderRespVO
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO
;
import
com.luhu.computility.module.pay.controller.app.order.vo.PayOrderWpgjRespVO
;
import
com.luhu.computility.module.pay.convert.order.PayOrderConvert
;
import
com.luhu.computility.module.pay.convert.order.PayOrderConvert
;
import
com.luhu.computility.module.pay.dal.dataobject.order.PayOrderDO
;
import
com.luhu.computility.module.pay.dal.dataobject.order.PayOrderDO
;
import
com.luhu.computility.module.pay.dal.dataobject.wallet.PayWalletDO
;
import
com.luhu.computility.module.pay.dal.dataobject.wallet.PayWalletDO
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
import
com.luhu.computility.module.pay.enums.PayChannelEnum
;
import
com.luhu.computility.module.pay.enums.PayChannelEnum
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
import
com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wallet.WalletPayClient
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wallet.WalletPayClient
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.service.order.PayOrderService
;
import
com.luhu.computility.module.pay.service.wallet.PayWalletService
;
import
com.luhu.computility.module.pay.service.wallet.PayWalletService
;
import
com.luhu.computility.module.pay.service.wpgj.PayOrderWpgjService
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Maps
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Parameter
;
import
io.swagger.v3.oas.annotations.Parameter
;
...
@@ -42,6 +46,8 @@ public class AppPayOrderController {
...
@@ -42,6 +46,8 @@ public class AppPayOrderController {
private
PayOrderService
payOrderService
;
private
PayOrderService
payOrderService
;
@Resource
@Resource
private
PayWalletService
payWalletService
;
private
PayWalletService
payWalletService
;
@Resource
private
PayOrderWpgjService
payOrderWpgjService
;
@GetMapping
(
"/get"
)
@GetMapping
(
"/get"
)
@Operation
(
summary
=
"获得支付订单"
)
@Operation
(
summary
=
"获得支付订单"
)
...
@@ -78,4 +84,15 @@ public class AppPayOrderController {
...
@@ -78,4 +84,15 @@ public class AppPayOrderController {
return
success
(
PayOrderConvert
.
INSTANCE
.
convert3
(
respVO
));
return
success
(
PayOrderConvert
.
INSTANCE
.
convert3
(
respVO
));
}
}
@GetMapping
(
"/wpgj-get"
)
@Operation
(
summary
=
"获得WPGJ旺铺聚合支付订单"
)
@Parameter
(
name
=
"id"
,
description
=
"WPGJ订单ID"
,
required
=
true
,
example
=
"1024"
)
public
CommonResult
<
PayOrderWpgjRespVO
>
getWpgjOrder
(
@RequestParam
(
"id"
)
Long
id
)
{
PayOrderWpgjDO
order
=
payOrderWpgjService
.
getById
(
id
);
if
(
order
==
null
)
{
return
success
(
new
PayOrderWpgjRespVO
());
}
return
success
(
BeanUtils
.
toBean
(
order
,
PayOrderWpgjRespVO
.
class
));
}
}
}
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java
View file @
842a425c
...
@@ -15,4 +15,7 @@ public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO {
...
@@ -15,4 +15,7 @@ public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO {
@Schema
(
description
=
"订单扩展ID(用于前端轮询支付状态)"
,
example
=
"123456"
)
@Schema
(
description
=
"订单扩展ID(用于前端轮询支付状态)"
,
example
=
"123456"
)
private
Long
orderExtensionId
;
private
Long
orderExtensionId
;
@Schema
(
description
=
"WPGJ订单ID(用于前端轮询WPGJ支付状态)"
,
example
=
"123456"
)
private
Long
wpgjOrderId
;
}
}
computility-module-pay/src/main/java/com/luhu/computility/module/pay/controller/app/order/vo/PayOrderWpgjRespVO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
controller
.
app
.
order
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.time.LocalDateTime
;
/**
* 用户 APP - WPGJ旺铺聚合支付订单 Response VO
*
* @author jonyl
*/
@Schema
(
description
=
"用户 APP - WPGJ旺铺聚合支付订单 Response VO"
)
@Data
public
class
PayOrderWpgjRespVO
{
@Schema
(
description
=
"订单编号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"1895381951077651000"
)
private
Long
id
;
@Schema
(
description
=
"业务类型 1-算力资源订单 2-API订单"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"1"
)
private
Integer
businessType
;
@Schema
(
description
=
"商户订单ID"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"123456"
)
private
String
merOrderId
;
@Schema
(
description
=
"旺铺订单号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"WPGJ123456789"
)
private
String
orderId
;
@Schema
(
description
=
"网关商户订单号"
,
example
=
"GW123456"
)
private
String
gatewayMerOrderId
;
@Schema
(
description
=
"关联的业务订单号"
,
example
=
"123456"
)
private
String
orderNo
;
@Schema
(
description
=
"内部商户号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"M123456"
)
private
String
merNo
;
@Schema
(
description
=
"商户代码"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"C123456"
)
private
String
merCode
;
@Schema
(
description
=
"设备SN号"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"SN123456789"
)
private
String
deviceNo
;
@Schema
(
description
=
"支付通道代码"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"wx_native"
)
private
String
paywayCode
;
@Schema
(
description
=
"下单时间"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"20241028143000"
)
private
String
orderTime
;
@Schema
(
description
=
"订单金额"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"100"
)
private
String
orderAmt
;
@Schema
(
description
=
"结算金额"
,
example
=
"99"
)
private
String
actAmt
;
@Schema
(
description
=
"手续费"
,
example
=
"1"
)
private
String
fee
;
@Schema
(
description
=
"订单状态 0-处理中 1-支付成功 2-支付失败"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"1"
)
private
String
orderStatus
;
@Schema
(
description
=
"通道交易流水号"
,
example
=
"TXN123456789"
)
private
String
tradeNo
;
@Schema
(
description
=
"交易时间"
,
example
=
"20241028143030"
)
private
String
tradeTime
;
@Schema
(
description
=
"订单标题"
,
example
=
"算力资源 - 7天"
)
private
String
orderTitle
;
@Schema
(
description
=
"买家用户号"
,
example
=
"U123456"
)
private
String
buyerId
;
@Schema
(
description
=
"微信/支付宝小票交易单号"
,
example
=
"TXN123456789"
)
private
String
tradeTopNo
;
@Schema
(
description
=
"交易账户类型 C-贷记卡 D-借记卡 U-未知"
,
example
=
"D"
)
private
String
cardType
;
@Schema
(
description
=
"报文签名值"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"ABC123"
)
private
String
sign
;
@Schema
(
description
=
"创建时间"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
LocalDateTime
createTime
;
@Schema
(
description
=
"更新时间"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
LocalDateTime
updateTime
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/dal/dataobject/wpgj/PayOrderWpgjDO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
dal
.
dataobject
.
wpgj
;
import
com.luhu.computility.framework.mybatis.core.dataobject.BaseDO
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.*
;
/**
* 旺铺聚合支付订单 DO
*
* @author jonyl
*/
@TableName
(
"pay_order_wpgj"
)
@Data
@EqualsAndHashCode
(
callSuper
=
true
)
@ToString
(
callSuper
=
true
)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
PayOrderWpgjDO
extends
BaseDO
{
/**
* 订单编号,自增
*/
@TableId
private
Long
id
;
/**
* 业务类型 1-算力资源订单 2-API订单
*/
private
Integer
businessType
;
/**
* 商户订单ID
*/
private
String
merOrderId
;
/**
* 旺铺订单号
*/
private
String
orderId
;
/**
* 网关商户订单号
*/
private
String
gatewayMerOrderId
;
/**
* 关联的业务订单号
*/
private
String
orderNo
;
/**
* 内部商户号
*/
private
String
merNo
;
/**
* 商户代码
*/
private
String
merCode
;
/**
* 设备SN号
*/
private
String
deviceNo
;
/**
* 支付通道代码
*/
private
String
paywayCode
;
/**
* 下单时间
*/
private
String
orderTime
;
/**
* 订单金额
*/
private
String
orderAmt
;
/**
* 结算金额
*/
private
String
actAmt
;
/**
* 手续费
*/
private
String
fee
;
/**
* 订单状态 0-处理中 1-支付成功 2-支付失败
*/
private
String
orderStatus
;
/**
* 通道交易流水号
*/
private
String
tradeNo
;
/**
* 交易时间
*/
private
String
tradeTime
;
/**
* 订单标题
*/
private
String
orderTitle
;
/**
* 买家用户号
*/
private
String
buyerId
;
/**
* 微信/支付宝小票交易单号
*/
private
String
tradeTopNo
;
/**
* 交易账户类型 C-贷记卡 D-借记卡 U-未知
*/
private
String
cardType
;
/**
* 报文签名值
*/
private
String
sign
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/dal/mysql/wpgj/PayOrderWpgjMapper.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
dal
.
mysql
.
wpgj
;
import
com.luhu.computility.framework.mybatis.core.mapper.BaseMapperX
;
import
com.luhu.computility.framework.mybatis.core.query.LambdaQueryWrapperX
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
import
org.apache.ibatis.annotations.Mapper
;
/**
* 旺铺聚合支付订单 Mapper
*
* @author jonyl
*/
@Mapper
public
interface
PayOrderWpgjMapper
extends
BaseMapperX
<
PayOrderWpgjDO
>
{
default
PayOrderWpgjDO
selectByMerOrderId
(
String
merOrderId
)
{
return
selectOne
(
PayOrderWpgjDO:
:
getMerOrderId
,
merOrderId
);
}
default
PayOrderWpgjDO
selectByOrderId
(
String
orderId
)
{
return
selectOne
(
PayOrderWpgjDO:
:
getOrderId
,
orderId
);
}
default
PayOrderWpgjDO
selectByOrderNo
(
String
orderNo
)
{
return
selectOne
(
PayOrderWpgjDO:
:
getOrderNo
,
orderNo
);
}
}
\ No newline at end of file
computility-module-
compute/computility-module-compute-biz/src/main/java/com/luhu/computility/module/compute
/enums/WpgjOrderStatusEnum.java
→
computility-module-
pay/src/main/java/com/luhu/computility/module/pay
/enums/WpgjOrderStatusEnum.java
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
compute
.
enums
;
package
com
.
luhu
.
computility
.
module
.
pay
.
enums
;
import
com.luhu.computility.framework.common.core.ArrayValuable
;
import
com.luhu.computility.framework.common.core.ArrayValuable
;
import
lombok.AllArgsConstructor
;
import
lombok.AllArgsConstructor
;
...
...
computility-module-pay/src/main/java/com/luhu/computility/module/pay/enums/order/WpgjOrderStatusEnum.java
deleted
100644 → 0
View file @
fa76472d
package
com
.
luhu
.
computility
.
module
.
pay
.
enums
.
order
;
import
com.luhu.computility.framework.common.core.ArrayValuable
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
/**
* WPGJ旺铺聚合支付订单状态枚举
*
* @author jonyl
*/
@Getter
@AllArgsConstructor
public
enum
WpgjOrderStatusEnum
implements
ArrayValuable
<
String
>
{
PROCESSING
(
"0"
,
"处理中"
),
SUCCESS
(
"1"
,
"支付成功"
),
FAILED
(
"2"
,
"支付失败"
),
;
private
final
String
status
;
private
final
String
name
;
@Override
public
String
[]
array
()
{
return
new
String
[
0
];
}
/**
* 判断是否支付成功
*
* @param status 状态
* @return 是否支付成功
*/
public
static
boolean
isSuccess
(
String
status
)
{
return
SUCCESS
.
getStatus
().
equals
(
status
);
}
/**
* 判断是否支付失败或关闭
*
* @param status 状态
* @return 是否支付失败或关闭
*/
public
static
boolean
isFailedOrClosed
(
String
status
)
{
return
PROCESSING
.
getStatus
().
equals
(
status
)
||
FAILED
.
getStatus
().
equals
(
status
);
}
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/dto/order/WpgjBusinessDataDTO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
framework
.
pay
.
core
.
client
.
dto
.
order
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
/**
* WPGJ 业务数据 DTO
*
* @author jony
*/
@Data
@Accessors
(
chain
=
true
)
public
class
WpgjBusinessDataDTO
{
/**
* 商户唯一订单号
*/
@NotBlank
(
message
=
"商户订单号不能为空"
)
private
String
merOrderId
;
/**
* 订单金额(分)
*/
@NotBlank
(
message
=
"订单金额不能为空"
)
private
String
orderAmt
;
/**
* 订单标题
*/
private
String
orderTitle
;
/**
* 下单时间
*/
@NotBlank
(
message
=
"下单时间不能为空"
)
private
String
orderTime
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/framework/pay/core/client/dto/order/WpgjUnifiedOrderReqDTO.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
framework
.
pay
.
core
.
client
.
dto
.
order
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotNull
;
/**
* WPGJ 统一下单请求 DTO
*
* @author jony
*/
@Data
@Accessors
(
chain
=
true
)
public
class
WpgjUnifiedOrderReqDTO
{
/**
* 商户号
*/
@NotBlank
(
message
=
"商户号不能为空"
)
private
String
merNo
;
/**
* 商户代码
*/
@NotBlank
(
message
=
"商户代码不能为空"
)
private
String
merCode
;
/**
* 异步通知地址
*/
@NotBlank
(
message
=
"异步通知地址不能为空"
)
private
String
notifyUrl
;
/**
* 业务数据
*/
@NotBlank
(
message
=
"业务数据不能为空"
)
private
String
businessData
;
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/order/PayOrderService.java
View file @
842a425c
...
@@ -101,17 +101,7 @@ public interface PayOrderService {
...
@@ -101,17 +101,7 @@ public interface PayOrderService {
PayOrderSubmitRespVO
submitOrder
(
@Valid
PayOrderSubmitReqVO
reqVO
,
PayOrderSubmitRespVO
submitOrder
(
@Valid
PayOrderSubmitReqVO
reqVO
,
@NotEmpty
(
message
=
"提交 IP 不能为空"
)
String
userIp
);
@NotEmpty
(
message
=
"提交 IP 不能为空"
)
String
userIp
);
/**
* 提交旺铺聚合支付订单
* 此时,会发起旺铺聚合支付渠道的调用
*
* @param reqVO 提交请求
* @param userIp 提交 IP
* @return 提交结果
*/
AppPayOrderSubmitRespVO
submitWpgjOrder
(
@Valid
AppPayOrderSubmitReqVO
reqVO
,
@NotEmpty
(
message
=
"提交 IP 不能为空"
)
String
userIp
);
/**
/**
* 通知支付单成功
* 通知支付单成功
*
*
...
...
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/order/PayOrderServiceImpl.java
View file @
842a425c
...
@@ -14,8 +14,6 @@ import com.luhu.computility.framework.common.util.number.MoneyUtils;
...
@@ -14,8 +14,6 @@ import com.luhu.computility.framework.common.util.number.MoneyUtils;
import
com.luhu.computility.module.pay.framework.pay.core.client.PayClient
;
import
com.luhu.computility.module.pay.framework.pay.core.client.PayClient
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderRespDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjCryptoUtils
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
com.luhu.computility.framework.tenant.core.util.TenantUtils
;
import
com.luhu.computility.framework.tenant.core.util.TenantUtils
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderExportReqVO
;
import
com.luhu.computility.module.pay.controller.admin.order.vo.PayOrderExportReqVO
;
...
@@ -74,7 +72,7 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -74,7 +72,7 @@ public class PayOrderServiceImpl implements PayOrderService {
private
PayOrderExtensionMapper
orderExtensionMapper
;
private
PayOrderExtensionMapper
orderExtensionMapper
;
@Resource
@Resource
private
PayNoRedisDAO
noRedisDAO
;
private
PayNoRedisDAO
noRedisDAO
;
@Resource
@Resource
private
PayAppService
appService
;
private
PayAppService
appService
;
@Resource
@Resource
...
@@ -82,9 +80,7 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -82,9 +80,7 @@ public class PayOrderServiceImpl implements PayOrderService {
@Resource
@Resource
private
PayNotifyService
notifyService
;
private
PayNotifyService
notifyService
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@Override
@Override
public
PayOrderDO
getOrder
(
Long
id
)
{
public
PayOrderDO
getOrder
(
Long
id
)
{
return
payOrderMapper
.
selectById
(
id
);
return
payOrderMapper
.
selectById
(
id
);
...
@@ -146,30 +142,11 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -146,30 +142,11 @@ public class PayOrderServiceImpl implements PayOrderService {
@Override
@Override
public
Long
createOrderWpgj
(
PayOrderCreateReqDTO
reqDTO
)
{
public
Long
createOrderWpgj
(
PayOrderCreateReqDTO
reqDTO
)
{
// 校验 App
// WPGJ订单已迁移到API层,这里提供兼容性实现
PayAppDO
app
=
appService
.
validPayApp
(
reqDTO
.
getAppKey
());
throw
new
UnsupportedOperationException
(
"WPGJ订单创建已迁移到PayOrderApi,请使用PayOrderApi.createOrderWpgj"
);
// 查询对应的支付交易单是否已经存在。如果是,则直接返回
PayOrderDO
order
=
payOrderMapper
.
selectByAppIdAndMerchantOrderId
(
app
.
getId
(),
reqDTO
.
getMerchantOrderId
());
if
(
order
!=
null
)
{
log
.
warn
(
"[createOrderWpgj][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]"
,
order
.
getAppId
(),
order
.
getMerchantOrderId
(),
toJsonString
(
order
));
// 理论来说,不会出现这个情况
return
order
.
getId
();
}
// 创建WPGJ支付交易单,使用WPGJ专用回调URL
order
=
PayOrderConvert
.
INSTANCE
.
convert
(
reqDTO
).
setAppId
(
app
.
getId
())
// 商户相关字段 - 使用WPGJ专用回调URL
.
setNotifyUrl
(
wpgjPayProperties
.
getNotifyUrl
())
// 订单相关字段
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
())
// 退款相关字段
.
setRefundPrice
(
0
);
payOrderMapper
.
insert
(
order
);
return
order
.
getId
();
}
}
@Override
// 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了
@Override
// 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了
public
PayOrderSubmitRespVO
submitOrder
(
PayOrderSubmitReqVO
reqVO
,
String
userIp
)
{
public
PayOrderSubmitRespVO
submitOrder
(
PayOrderSubmitReqVO
reqVO
,
String
userIp
)
{
// 1.1 获得 PayOrderDO ,并校验其是否存在
// 1.1 获得 PayOrderDO ,并校验其是否存在
...
@@ -218,154 +195,9 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -218,154 +195,9 @@ public class PayOrderServiceImpl implements PayOrderService {
return
PayOrderConvert
.
INSTANCE
.
convert
(
order
,
unifiedOrderResp
);
return
PayOrderConvert
.
INSTANCE
.
convert
(
order
,
unifiedOrderResp
);
}
}
/**
* 提交旺铺聚合支付订单
*
* @param reqVO 支付提交请求
* @param userIp 用户 IP
* @return 支付提交响应
*/
// 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了
public
AppPayOrderSubmitRespVO
submitWpgjOrder
(
AppPayOrderSubmitReqVO
reqVO
,
String
userIp
)
{
// 1.1 获得 PayOrderDO ,并校验其是否存在
PayOrderDO
order
=
validateOrderCanSubmit
(
reqVO
.
getId
());
// 2. 插入 PayOrderExtensionDO
String
no
=
noRedisDAO
.
generate
(
payProperties
.
getOrderNoPrefix
());
PayOrderExtensionDO
orderExtension
=
PayOrderConvert
.
INSTANCE
.
convert
(
reqVO
,
userIp
)
.
setOrderId
(
order
.
getId
()).
setNo
(
no
)
.
setChannelId
(-
1L
).
setChannelCode
(
"wpgj_dynamic"
)
// 使用-1表示WPGJ特殊渠道,避免在validateOrderActuallyPaid中查找PayClient
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
());
orderExtensionMapper
.
insert
(
orderExtension
);
// 3. 直接调用WPGJ API
PayOrderRespDTO
unifiedOrderResp
=
callWpgjApi
(
order
,
orderExtension
,
reqVO
,
userIp
);
// 4. 构建返回结果
AppPayOrderSubmitRespVO
appRespVO
=
new
AppPayOrderSubmitRespVO
();
if
(
unifiedOrderResp
!=
null
)
{
appRespVO
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
());
appRespVO
.
setDisplayMode
(
unifiedOrderResp
.
getDisplayMode
());
appRespVO
.
setDisplayContent
(
unifiedOrderResp
.
getDisplayContent
());
}
else
{
appRespVO
.
setStatus
(
order
.
getStatus
());
}
return
appRespVO
;
}
/**
* 调用WPGJ支付API - 按照demo代码标准实现动态支付序列码接口
*/
private
PayOrderRespDTO
callWpgjApi
(
PayOrderDO
order
,
PayOrderExtensionDO
orderExtension
,
AppPayOrderSubmitReqVO
reqVO
,
String
userIp
)
{
try
{
log
.
info
(
"[callWpgjApi] 开始调用WPGJ支付API,订单号: {}"
,
orderExtension
.
getNo
());
// 1. 构建业务数据 - 按照demo的testDynamicOrder方法
JSONObject
businessData
=
new
JSONObject
();
businessData
.
set
(
"mer_no"
,
wpgjPayProperties
.
getMerNo
());
businessData
.
set
(
"mer_code"
,
wpgjPayProperties
.
getMerCode
());
businessData
.
set
(
"term_code"
,
wpgjPayProperties
.
getTermCode
());
businessData
.
set
(
"mer_order_id"
,
orderExtension
.
getNo
());
// 商户唯一订单号
businessData
.
set
(
"order_amt"
,
String
.
valueOf
(
order
.
getPrice
()
/
100.0
));
// 转换为元,保留两位小数
businessData
.
set
(
"organiz_no"
,
wpgjPayProperties
.
getOrganizNo
());
businessData
.
set
(
"cashier_type"
,
"1"
);
// 收银台模板
businessData
.
set
(
"return_url"
,
reqVO
.
getReturnUrl
());
businessData
.
set
(
"notifyurl"
,
wpgjPayProperties
.
getNotifyUrl
());
// 2. 构建加密请求数据 - 按照demo标准
String
encryptedRequest
=
WpgjCryptoUtils
.
buildEncryptedRequest
(
businessData
,
wpgjPayProperties
.
getOrganizNo
(),
wpgjPayProperties
.
getPublicKey
()
);
// 3. URL编码 - 按照demo要求
String
encodedRequest
=
java
.
net
.
URLEncoder
.
encode
(
encryptedRequest
,
"UTF-8"
);
log
.
info
(
"[callWpgjApi] 发送加密请求数据: {}"
,
encryptedRequest
);
log
.
info
(
"[callWpgjApi] 请求URL: {}"
,
wpgjPayProperties
.
getApiUrl
());
// 4. 发送HTTP请求 - 按照demo方式
HttpResponse
response
=
HttpRequest
.
post
(
wpgjPayProperties
.
getApiUrl
())
.
header
(
"Content-Type"
,
"application/x-www-form-urlencoded"
)
.
body
(
encodedRequest
)
.
timeout
(
30000
)
.
execute
();
// 5. 处理响应
if
(!
response
.
isOk
())
{
log
.
error
(
"[callWpgjApi] WPGJ API调用失败,HTTP状态码: {}, 响应: {}"
,
response
.
getStatus
(),
response
.
body
());
throw
exception
(
PAY_ORDER_SUBMIT_CHANNEL_ERROR
,
"HTTP_ERROR"
,
"支付网关调用失败,状态码: "
+
response
.
getStatus
());
}
String
responseData
=
response
.
body
();
// 6. 解析响应结果 - 需要解密
JSONObject
responseJson
=
new
JSONObject
(
responseData
);
if
(
"0000"
.
equals
(
responseJson
.
getStr
(
"code"
)))
{
// 解密响应数据
JSONObject
decryptedResponse
=
WpgjCryptoUtils
.
decryptResponse
(
responseData
,
wpgjPayProperties
.
getPrivateKey
());
log
.
info
(
"[callWpgjApi] WPGJ API解密后的完整响应: {}"
,
decryptedResponse
);
return
parseWpgjApiResponse
(
decryptedResponse
,
orderExtension
.
getNo
());
}
else
{
// 处理错误响应
return
parseWpgjError
(
responseJson
,
orderExtension
.
getNo
());
}
}
catch
(
Exception
e
)
{
log
.
error
(
"[callWpgjApi] WPGJ API调用异常,订单号: {}"
,
orderExtension
.
getNo
(),
e
);
throw
exception
(
PAY_ORDER_SUBMIT_CHANNEL_ERROR
,
"API_ERROR"
,
"支付网关调用异常: "
+
e
.
getMessage
());
}
}
/**
* 解析WPGJ API成功响应 - 根据demo动态支付接口
*/
private
PayOrderRespDTO
parseWpgjApiResponse
(
JSONObject
response
,
String
outTradeNo
)
{
PayOrderRespDTO
respDTO
=
new
PayOrderRespDTO
();
respDTO
.
setOutTradeNo
(
outTradeNo
);
respDTO
.
setChannelCode
(
"wpgj_dynamic"
);
respDTO
.
setStatus
(
PayOrderStatusEnum
.
WAITING
.
getStatus
());
// 解析data字段中的payUrl(动态支付URL)
JSONObject
data
=
response
.
getJSONObject
(
"data"
);
if
(
data
!=
null
&&
data
.
containsKey
(
"payUrl"
))
{
String
payUrl
=
data
.
getStr
(
"payUrl"
);
respDTO
.
setDisplayMode
(
"pay_url"
);
respDTO
.
setDisplayContent
(
payUrl
);
log
.
info
(
"[parseWpgjApiResponse] 获取到支付URL: {}"
,
payUrl
);
}
respDTO
.
setRawData
(
JSONUtil
.
toJsonStr
(
response
));
return
respDTO
;
}
/**
* 解析WPGJ API错误响应
*/
private
PayOrderRespDTO
parseWpgjError
(
JSONObject
response
,
String
outTradeNo
)
{
PayOrderRespDTO
respDTO
=
new
PayOrderRespDTO
();
respDTO
.
setOutTradeNo
(
outTradeNo
);
respDTO
.
setChannelCode
(
"wpgj_dynamic"
);
respDTO
.
setStatus
(
PayOrderStatusEnum
.
CLOSED
.
getStatus
());
// 错误时设置为关闭状态
// 设置错误信息
respDTO
.
setChannelErrorCode
(
response
.
getStr
(
"code"
));
respDTO
.
setChannelErrorMsg
(
response
.
getStr
(
"msg"
));
respDTO
.
setRawData
(
JSONUtil
.
toJsonStr
(
response
));
log
.
error
(
"[parseWpgjError] WPGJ API返回错误: code={}, msg={}"
,
response
.
getStr
(
"code"
),
response
.
getStr
(
"msg"
));
return
respDTO
;
}
private
PayOrderDO
validateOrderCanSubmit
(
Long
id
)
{
private
PayOrderDO
validateOrderCanSubmit
(
Long
id
)
{
PayOrderDO
order
=
payOrderMapper
.
selectById
(
id
);
PayOrderDO
order
=
payOrderMapper
.
selectById
(
id
);
...
@@ -405,11 +237,6 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -405,11 +237,6 @@ public class PayOrderServiceImpl implements PayOrderService {
// 情况二:调用三方接口,查询支付单状态,是不是已支付
// 情况二:调用三方接口,查询支付单状态,是不是已支付
PayClient
<?>
payClient
=
channelService
.
getPayClient
(
orderExtension
.
getChannelId
());
PayClient
<?>
payClient
=
channelService
.
getPayClient
(
orderExtension
.
getChannelId
());
if
(
payClient
==
null
)
{
if
(
payClient
==
null
)
{
// WPGJ特殊渠道,没有PayClient,跳过查询
if
(
orderExtension
.
getChannelId
()
==
-
1L
&&
"wpgj_dynamic"
.
equals
(
orderExtension
.
getChannelCode
()))
{
log
.
debug
(
"[validateOrderCanSubmit][WPGJ渠道({}) 跳过支付状态查询]"
,
orderExtension
.
getChannelId
());
return
;
}
log
.
error
(
"[validateOrderCanSubmit][渠道编号({}) 找不到对应的支付客户端]"
,
orderExtension
.
getChannelId
());
log
.
error
(
"[validateOrderCanSubmit][渠道编号({}) 找不到对应的支付客户端]"
,
orderExtension
.
getChannelId
());
return
;
return
;
}
}
...
@@ -447,132 +274,16 @@ public class PayOrderServiceImpl implements PayOrderService {
...
@@ -447,132 +274,16 @@ public class PayOrderServiceImpl implements PayOrderService {
@Override
@Override
public
void
notifyOrder
(
Long
channelId
,
PayOrderRespDTO
notify
)
{
public
void
notifyOrder
(
Long
channelId
,
PayOrderRespDTO
notify
)
{
// WPGJ特殊渠道处理
if
(
channelId
==
-
1L
&&
"wpgj_dynamic"
.
equals
(
notify
.
getChannelCode
()))
{
log
.
info
(
"[notifyOrder][WPGJ特殊渠道] 处理支付通知: {}"
,
JSONUtil
.
toJsonStr
(
notify
));
getSelf
().
notifyWpgjOrder
(
notify
);
return
;
}
// 原有渠道处理
PayChannelDO
channel
=
channelService
.
validPayChannel
(
channelId
);
PayChannelDO
channel
=
channelService
.
validPayChannel
(
channelId
);
// 更新支付订单为已支付
// 更新支付订单为已支付
TenantUtils
.
execute
(
channel
.
getTenantId
(),
()
->
getSelf
().
notifyOrder
(
channel
,
notify
));
TenantUtils
.
execute
(
channel
.
getTenantId
(),
()
->
getSelf
().
notifyOrder
(
channel
,
notify
));
}
}
/**
* 处理WPGJ旺铺聚合支付通知
*
* @param notify 支付结果通知
*/
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
notifyWpgjOrder
(
PayOrderRespDTO
notify
)
{
log
.
info
(
"[notifyWpgjOrder] 开始处理WPGJ支付通知: {}"
,
JSONUtil
.
toJsonStr
(
notify
));
// 情况一:支付成功的回调
if
(
PayOrderStatusEnum
.
isSuccess
(
notify
.
getStatus
()))
{
notifyWpgjOrderSuccess
(
notify
);
return
;
}
// 情况二:支付失败的回调
if
(
PayOrderStatusEnum
.
isClosed
(
notify
.
getStatus
()))
{
notifyWpgjOrderClosed
(
notify
);
}
// 情况三:WAITING:无需处理
log
.
info
(
"[notifyWpgjOrder] WPGJ支付通知处理完成,状态: {}"
,
notify
.
getStatus
());
}
/**
* 处理WPGJ支付成功通知
*/
private
void
notifyWpgjOrderSuccess
(
PayOrderRespDTO
notify
)
{
// 1. 更新 PayOrderExtensionDO 支付成功
PayOrderExtensionDO
orderExtension
=
updateOrderSuccess
(
notify
);
// 2. 更新 PayOrderDO 支付成功(使用WPGJ特殊渠道参数)
updateWpgjOrderSuccess
(
orderExtension
,
notify
);
// 3. 插入支付通知记录
notifyService
.
createPayNotifyTask
(
PayNotifyTypeEnum
.
ORDER
.
getType
(),
orderExtension
.
getOrderId
());
log
.
info
(
"[notifyWpgjOrderSuccess] WPGJ支付成功通知处理完成,订单ID: {}"
,
orderExtension
.
getOrderId
());
}
/**
* 处理WPGJ支付关闭通知
*/
private
void
notifyWpgjOrderClosed
(
PayOrderRespDTO
notify
)
{
updateWpgjOrderClosed
(
notify
);
log
.
info
(
"[notifyWpgjOrderClosed] WPGJ支付关闭通知处理完成"
);
}
/**
* 更新WPGJ PayOrderDO 支付成功
*/
private
void
updateWpgjOrderSuccess
(
PayOrderExtensionDO
orderExtension
,
PayOrderRespDTO
notify
)
{
// 1. 判断 PayOrderDO 是否处于待支付
PayOrderDO
order
=
payOrderMapper
.
selectById
(
orderExtension
.
getOrderId
());
if
(
order
==
null
)
{
throw
exception
(
PAY_ORDER_NOT_FOUND
);
}
if
(
PayOrderStatusEnum
.
isSuccess
(
order
.
getStatus
())
// 如果已经是成功,直接返回,不用重复更新
&&
Objects
.
equals
(
order
.
getExtensionId
(),
orderExtension
.
getId
()))
{
log
.
info
(
"[updateWpgjOrderSuccess][order({}) 已经是已支付,无需更新]"
,
order
.
getId
());
return
;
}
if
(!
PayOrderStatusEnum
.
WAITING
.
getStatus
().
equals
(
order
.
getStatus
()))
{
// 校验状态,必须是待支付
throw
exception
(
PAY_ORDER_STATUS_IS_NOT_WAITING
);
}
// 2. 更新 PayOrderDO(使用WPGJ固定参数)
int
updateCounts
=
payOrderMapper
.
updateByIdAndStatus
(
order
.
getId
(),
PayOrderStatusEnum
.
WAITING
.
getStatus
(),
PayOrderDO
.
builder
().
status
(
PayOrderStatusEnum
.
SUCCESS
.
getStatus
())
.
channelId
(-
1L
).
channelCode
(
"wpgj_dynamic"
)
.
successTime
(
notify
.
getSuccessTime
()).
extensionId
(
orderExtension
.
getId
()).
no
(
orderExtension
.
getNo
())
.
channelOrderNo
(
notify
.
getChannelOrderNo
()).
channelUserId
(
notify
.
getChannelUserId
())
.
channelFeeRate
(
0.0
)
// WPGJ手续费暂时设为0
.
channelFeePrice
(
0
)
.
build
());
if
(
updateCounts
==
0
)
{
// 校验状态,必须是待支付
throw
exception
(
PAY_ORDER_STATUS_IS_NOT_WAITING
);
}
log
.
info
(
"[updateWpgjOrderSuccess][order({}) 更新为已支付]"
,
order
.
getId
());
}
/**
* 更新WPGJ PayOrderExtensionDO 关闭
*/
private
void
updateWpgjOrderClosed
(
PayOrderRespDTO
notify
)
{
// 1. 查询 PayOrderExtensionDO
PayOrderExtensionDO
orderExtension
=
orderExtensionMapper
.
selectByNo
(
notify
.
getOutTradeNo
());
if
(
orderExtension
==
null
)
{
log
.
warn
(
"[updateWpgjOrderClosed] 找不到PayOrderExtensionDO,订单号: {}"
,
notify
.
getOutTradeNo
());
return
;
}
if
(
PayOrderStatusEnum
.
isClosed
(
orderExtension
.
getStatus
()))
{
// 如果已经是关闭,直接返回,不用重复更新
log
.
info
(
"[updateWpgjOrderClosed][orderExtension({}) 已经是支付关闭,无需更新]"
,
orderExtension
.
getId
());
return
;
}
// 一般出现先是支付成功,然后支付关闭,都是全部退款导致关闭的场景。这个情况,我们不更新支付拓展单,只通过退款流程,更新支付单
if
(
PayOrderStatusEnum
.
isSuccess
(
orderExtension
.
getStatus
()))
{
log
.
info
(
"[updateWpgjOrderClosed][orderExtension({}) 是已支付,无需更新为支付关闭]"
,
orderExtension
.
getId
());
return
;
}
if
(
ObjectUtil
.
notEqual
(
orderExtension
.
getStatus
(),
PayOrderStatusEnum
.
WAITING
.
getStatus
()))
{
// 校验状态,必须是待支付
log
.
warn
(
"[updateWpgjOrderClosed][orderExtension({}) 状态不是待支付,无需更新: {}"
,
orderExtension
.
getId
(),
orderExtension
.
getStatus
());
return
;
}
// 2. 更新 PayOrderExtensionDO
int
updateCounts
=
orderExtensionMapper
.
updateByIdAndStatus
(
orderExtension
.
getId
(),
orderExtension
.
getStatus
(),
PayOrderExtensionDO
.
builder
().
status
(
PayOrderStatusEnum
.
CLOSED
.
getStatus
()).
channelNotifyData
(
toJsonString
(
notify
))
.
channelErrorCode
(
notify
.
getChannelErrorCode
()).
channelErrorMsg
(
notify
.
getChannelErrorMsg
()).
build
());
if
(
updateCounts
==
0
)
{
// 校验状态,必须是待支付
log
.
warn
(
"[updateWpgjOrderClosed][orderExtension({}) 更新失败,可能状态已变更]"
,
orderExtension
.
getId
());
return
;
}
log
.
info
(
"[updateWpgjOrderClosed][orderExtension({}) 更新为支付关闭]"
,
orderExtension
.
getId
());
}
/**
/**
* 通知并更新订单的支付结果
* 通知并更新订单的支付结果
*
*
...
...
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/wpgj/PayOrderWpgjService.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
service
.
wpgj
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
/**
* 旺铺聚合支付订单 Service 接口
*
* @author jonyl
*/
public
interface
PayOrderWpgjService
{
/**
* 保存旺铺聚合支付订单回调数据
*
* @param notifyDTO WPGJ回调数据
* @return 订单ID
*/
Long
saveOrder
(
WpgjPayNotifyDTO
notifyDTO
);
/**
* 根据商户订单ID获取旺铺聚合支付订单
*
* @param merOrderId 商户订单ID (对应compute_resource_order.id)
* @return 旺铺聚合支付订单
*/
PayOrderWpgjDO
getByMerOrderId
(
String
merOrderId
);
/**
* 根据旺铺订单ID获取旺铺聚合支付订单
*
* @param orderId 旺铺订单ID
* @return 旺铺聚合支付订单
*/
PayOrderWpgjDO
getByOrderId
(
String
orderId
);
/**
* 根据主键ID获取旺铺聚合支付订单
*
* @param id 主键ID
* @return 旺铺聚合支付订单
*/
PayOrderWpgjDO
getById
(
Long
id
);
}
\ No newline at end of file
computility-module-pay/src/main/java/com/luhu/computility/module/pay/service/wpgj/PayOrderWpgjServiceImpl.java
0 → 100644
View file @
842a425c
package
com
.
luhu
.
computility
.
module
.
pay
.
service
.
wpgj
;
import
cn.hutool.core.util.StrUtil
;
import
com.luhu.computility.framework.common.util.object.BeanUtils
;
import
com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO
;
import
com.luhu.computility.module.pay.dal.dataobject.wpgj.PayOrderWpgjDO
;
import
com.luhu.computility.module.pay.dal.mysql.wpgj.PayOrderWpgjMapper
;
import
com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.validation.annotation.Validated
;
import
javax.annotation.Resource
;
/**
* 旺铺聚合支付订单 Service 实现类
*
* @author jonyl
*/
@Service
@Validated
@Slf4j
public
class
PayOrderWpgjServiceImpl
implements
PayOrderWpgjService
{
@Resource
private
PayOrderWpgjMapper
payOrderWpgjMapper
;
@Resource
private
WpgjPayProperties
wpgjPayProperties
;
@Override
public
Long
saveOrder
(
WpgjPayNotifyDTO
notifyDTO
)
{
// 查询是否已存在相同商户订单ID的记录
PayOrderWpgjDO
existingOrder
=
payOrderWpgjMapper
.
selectByMerOrderId
(
notifyDTO
.
getMerOrderId
());
if
(
existingOrder
!=
null
)
{
log
.
info
(
"[saveOrder] WPGJ订单已存在,商户订单ID: {}, 更新订单状态"
,
notifyDTO
.
getMerOrderId
());
// 更新现有订单的状态和信息
PayOrderWpgjDO
updateOrder
=
BeanUtils
.
toBean
(
notifyDTO
,
PayOrderWpgjDO
.
class
);
updateOrder
.
setId
(
existingOrder
.
getId
());
updateOrder
.
setOrderStatus
(
notifyDTO
.
getOrderStatus
());
payOrderWpgjMapper
.
updateById
(
updateOrder
);
return
existingOrder
.
getId
();
}
// 创建新订单记录
PayOrderWpgjDO
payOrderWpgj
=
BeanUtils
.
toBean
(
notifyDTO
,
PayOrderWpgjDO
.
class
);
payOrderWpgj
.
setBusinessType
(
1
);
// 1-算力资源订单
payOrderWpgj
.
setOrderNo
(
notifyDTO
.
getMerOrderId
());
// 商户订单ID作为业务订单号
// 从配置中获取可能为空的必填字段
if
(
StrUtil
.
isBlank
(
payOrderWpgj
.
getMerCode
()))
{
payOrderWpgj
.
setMerCode
(
wpgjPayProperties
.
getMerCode
());
log
.
info
(
"[saveOrder] 使用配置中的merCode: {}"
,
wpgjPayProperties
.
getMerCode
());
}
payOrderWpgjMapper
.
insert
(
payOrderWpgj
);
log
.
info
(
"[saveOrder] WPGJ订单保存成功,订单ID: {}, 商户订单ID: {}"
,
payOrderWpgj
.
getId
(),
notifyDTO
.
getMerOrderId
());
return
payOrderWpgj
.
getId
();
}
@Override
public
PayOrderWpgjDO
getByMerOrderId
(
String
merOrderId
)
{
return
payOrderWpgjMapper
.
selectByMerOrderId
(
merOrderId
);
}
@Override
public
PayOrderWpgjDO
getByOrderId
(
String
orderId
)
{
return
payOrderWpgjMapper
.
selectByOrderId
(
orderId
);
}
@Override
public
PayOrderWpgjDO
getById
(
Long
id
)
{
return
payOrderWpgjMapper
.
selectById
(
id
);
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment